想到推薦演演算法,大家可能會想到電商和遊戲。不過,隨著短影片產品的崛起,推薦演演算法也迎來一個新的風口,被大量應用在短影片領域,吸引更多的使用者看到自己喜歡的內容。
2019 年 2 月,ICME 2019 短影片內容理解與推薦競賽正式開放提交。本次比賽掛靠多媒體領域的頂會 IEEE ICME,主題為預測使用者是否看完及點贊一個短影片。
比賽連結:
https://biendata.com/competition/icmechallenge2019/
比賽獎金:2 萬美元
時間:2019 年 2 月 11 日 – 2019 年 4 月 7 日
背景
“一圖勝千言”,僅僅一張圖片就包含大量資訊,難以用幾個詞來描述。更不用說短影片了。所以,雖然機器學習近年來在影象識別、語音識別等領域取得了重大進步,但在影片內容理解領域仍有許多問題需要探索。
不過,目前也有不少相關研究。2016 年,谷歌 YouTube 團隊在 ACM RecSys 會議上發表論文 Deep Neural Networks for YouTube Recommendations,詳細介紹了不少 YouTube 影片推薦功能的技術細節。
比賽資料與賽道
為了方便大家參賽,ICME 2019 短影片內容理解與推薦競賽的主辦方已經提取出了多種型別的短影片內容特徵,包括視覺特徵、文字特徵和音訊特徵。
此外,為了方便不同背景的參賽者參加比賽,本次比賽按照資料量分成兩個賽道(資料格式和預測任務都相同):
賽道 1:大規模資料集,億級別的資料資訊。
賽道2:小規模資料集,千萬級別的資料資訊。
評測方法
參賽選手需要預測測試資料中每一條資料的點選(finish+like)機率。本次比賽使用 AUC(ROC 曲線下麵積)作為評估指標。AUC 越高,代表結果越優,排名越靠前。在總分中,finish 和 like 的分配比例是:0.7*finish+0.3*like。
Baseline程式碼
在 TRACK 2 上,baseline 的結果分別為 like:86.5%,finish:69.8%。
Baseline 需要 TensorFlow 1.12.0。模型下載地址:
https://github.com/challenge-ICME2019-Bytedance/Bytedance_ICME_challenge
baseline指令碼 & 程式碼說明
#——執行指令碼——#
train.sh
#——訓練模型——#
train.py
#——模型引數輸入——#
common/
model_args.py
#——tensorflow資料轉換輸入——#
data_io/
data_parser.py
#——模型準備與框架搭建——#
models/
model.py
#——fm推薦演演算法——#
model_zoo/
fm.py
#--utils資料處理——#
utils/
utils.py
Bytedance_ICME_challenge/model_zoo/fm.py
import tensorflow as tf
class FMModelParams(object):
"""初始化fm模型權重"""
def __init__(self, feature_size, embedding_size):
self._feature_size = feature_size
self._embedding_size = embedding_size
def initialize_weights(self):
""" 初始化fm權重
Returns
weights:
feature_embeddings: vi, vj second order params
weights_first_order: wi first order params
bias: b bias
"""
weights = dict()
weights_initializer=tf.glorot_normal_initializer()
bias_initializer=tf.constant_initializer(0.0)
weights["feature_embeddings"] = tf.get_variable(
name='weights',
dtype=tf.float32,
initializer=weights_initializer,
shape=[self._feature_size, self._embedding_size])
weights["weights_first_order"] = tf.get_variable(
name='vectors',
dtype=tf.float32,
initializer=weights_initializer,
shape=[self._feature_size, 1])
weights["fm_bias"] = tf.get_variable(
name='bias',
dtype=tf.float32,
initializer=bias_initializer,
shape=[1])
return weights
class FMModel(object):
"""fm實施"""
@staticmethod
def fm_model_fn(features, labels, mode, params):
"""建立tensorflow模型"""
#解析引數
embedding_size = params['embedding_size']
feature_size = params['feature_size']
batch_size = params['batch_size']
learning_rate = params['learning_rate']
field_size = params['field_size']
optimizer_used = params['optimizer']
#解析特徵
feature_idx = features["feature_idx"]
feature_idx = tf.reshape(feature_idx, shape=[batch_size, field_size])
labels = tf.reshape(labels, shape=[batch_size, 1])
feature_values = features["feature_values"]
feature_values = tf.reshape(feature_values, shape=[batch_size, field_size, 1])
# tensorflow fm 權重
tf_model_params = FMModelParams(feature_size, embedding_size)
weights = tf_model_params.initialize_weights()
embeddings = tf.nn.embedding_lookup(
weights["feature_embeddings"],
feature_idx
)
weights_first_order = tf.nn.embedding_lookup(
weights["weights_first_order"],
feature_idx
)
bias = weights['fm_bias']
#構建函式
##first order
first_order = tf.multiply(feature_values, weights_first_order)
first_order = tf.reduce_sum(first_order, 2)
first_order = tf.reduce_sum(first_order, 1, keepdims=True)
##second order
### feature * embeddings
f_e_m = tf.multiply(feature_values, embeddings)
### square(sum(feature * embedding))
f_e_m_sum = tf.reduce_sum(f_e_m, 1)
f_e_m_sum_square = tf.square(f_e_m_sum)
### sum(square(feature * embedding))
f_e_m_square = tf.square(f_e_m)
f_e_m_square_sum = tf.reduce_sum(f_e_m_square, 1)
second_order = f_e_m_sum_square - f_e_m_square_sum
second_order = tf.reduce_sum(second_order, 1, keepdims=True)
##最終標的函式
logits = second_order + first_order + bias
predicts = tf.sigmoid(logits)
##損失函式
sigmoid_loss = tf.nn.sigmoid_cross_entropy_with_logits(logits=logits, labels=labels)
sigmoid_loss = tf.reduce_mean(sigmoid_loss)
loss = sigmoid_loss
#訓練操作
if optimizer_used == 'adagrad':
optimizer = tf.train.AdagradOptimizer(
learning_rate=learning_rate,
initial_accumulator_value=1e-8)
elif optimizer_used == 'adam':
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
else:
raise Exception("unknown optimizer", optimizer_used)
train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
#計算auc
eval_metric_ops = {
"auc": tf.metrics.auc(labels, predicts)
}
predictions = {"prob": predicts}
return tf.estimator.EstimatorSpec(
mode=tf.estimator.ModeKeys.TRAIN,
predictions=predicts,
loss=loss,
eval_metric_ops=eval_metric_ops,
train_op=train_op)
Bytedance_ICME_challenge/models/model.py
""" import necessary packages"""
import tensorflow as tf
from data_io.data_parser import PosShifts, LineParser
from model_zoo.fm import FMModel
class RecommendModelHandler(object):
"""設定推薦模型的類"""
def __init__(self, train_dataset_path, val_dataset_path, save_model_dir, \
learning_rate=0.1, num_threads=1, num_epochs=100, batch_size=40, \
embedding_size=100, optimizer='adam', task="finish", track=2):
"""初始化基本引數"""
self._learning_rate = learning_rate
self._num_threads = num_threads
self._num_epochs = num_epochs
self._batch_size = batch_size
self._train_dataset_path = train_dataset_path
self._val_dataset_path = val_dataset_path
self._save_model_dir = save_model_dir
self._embedding_size = embedding_size
self._optimizer = optimizer
self._task = task
self._track = track
def build_model(self):
"""建立推薦模型框架"""
config = tf.estimator.RunConfig().replace(
session_config=tf.ConfigProto(device_count={'CPU':self._num_threads}),
log_step_count_steps=20)
PosShifts(self._track)
feature_size = PosShifts.get_features_num()
params={
'feature_size': feature_size,
'embedding_size': self._embedding_size,
'learning_rate': self._learning_rate,
'field_size': 5,
'batch_size': self._batch_size,
'optimizer': self._optimizer}
model = tf.estimator.Estimator(
model_fn=FMModel.fm_model_fn,
model_dir=self._save_model_dir,
params=params,
config=config)
return model
def prepare_data_fn(self, data_mode='train'):
"""準備訓練/驗證資料"""
if data_mode == 'train':
dataset = tf.data.TextLineDataset(self._train_dataset_path)
elif data_mode == 'val':
dataset = tf.data.TextLineDataset(self._val_dataset_path)
else:
raise Exception("unknown data_mode", data_mode)
if self._task == "finish":
dataset = dataset.map(LineParser.parse_finish_line)
elif self._task == "like":
dataset = dataset.map(LineParser.parse_like_line)
else:
raise Exception("unknown task", task)
dataset = dataset.shuffle(buffer_size=300)
dataset = dataset.repeat(self._num_epochs)
dataset = dataset.batch(self._batch_size)
data_iterator = dataset.make_one_shot_iterator()
idx, features, labels = data_iterator.get_next()
feature_infos = {}
feature_infos['feature_idx'] = idx
feature_infos['feature_values'] = features
tf.logging.info(labels)
return feature_infos, labels
def train(self):
"""訓練模型"""
model = self.build_model()
train_spec = tf.estimator.TrainSpec(input_fn=lambda: self.prepare_data_fn(data_mode='train'))
val_spec = tf.estimator.EvalSpec(input_fn=lambda: self.prepare_data_fn(data_mode='val'))
tf.estimator.train_and_evaluate(model, train_spec, val_spec)
點選以下標題檢視更多往期內容:
#投 稿 通 道# 讓你的論文被更多人看到 如何才能讓更多的優質內容以更短路徑到達讀者群體,縮短讀者尋找優質內容的成本呢? 答案就是:你不認識的人。
總有一些你不認識的人,知道你想知道的東西。PaperWeekly 或許可以成為一座橋梁,促使不同背景、不同方向的學者和學術靈感相互碰撞,迸發出更多的可能性。
PaperWeekly 鼓勵高校實驗室或個人,在我們的平臺上分享各類優質內容,可以是最新論文解讀,也可以是學習心得或技術乾貨。我們的目的只有一個,讓知識真正流動起來。
? 來稿標準: • 稿件確系個人原創作品,來稿需註明作者個人資訊(姓名+學校/工作單位+學歷/職位+研究方向) • 如果文章並非首發,請在投稿時提醒並附上所有已釋出連結 • PaperWeekly 預設每篇文章都是首發,均會新增“原創”標誌
? 投稿郵箱: • 投稿郵箱:hr@paperweekly.site • 所有文章配圖,請單獨在附件中傳送 • 請留下即時聯絡方式(微信或手機),以便我們在編輯釋出時和作者溝通
?
現在,在「知乎」也能找到我們了
進入知乎首頁搜尋「PaperWeekly」
點選「關註」訂閱我們的專欄吧
關於PaperWeekly
PaperWeekly 是一個推薦、解讀、討論、報道人工智慧前沿論文成果的學術平臺。如果你研究或從事 AI 領域,歡迎在公眾號後臺點選「交流群」,小助手將把你帶入 PaperWeekly 的交流群裡。
▽ 點選 | 閱讀原文 | 加入比賽