2016年,YouTube发表了深度学习推荐系统论文Deep Neural Networks for YouTube Recommendations,这是一篇理论和实践俱佳的论文。从Matching到Ranking到线上serving的各个环节,论文都给出了Youtube的实践方法。总体框架如下:
在Youtube视频推荐场景下,考虑到如下特征(各个特征concat到一起后,送到后续的DNN中):
注:序列中ID的初始embedding,论文中是通过word2vec来获取的。
关于数据样本的选择:
关于如何训练,论文中说到对两种方式进行了实验,图(a)是hold-out方式,利用上下文信息预估中间的一个视频;图(b)是predicting future watch的方式,则是利用上文信息,预估下一次浏览的视频。发现图(b)的方式在线上A/B test中表现更佳。
YoutubeNet采用的训练方式是预测下一个视频ID,所以这是一个多分类问题,但是视频库里面的视频类别多达百万级,使用softmax无疑是低效的。Youtube采用类似于word2vec中的负采样优化算法,在非下一个watch的候选集合中采样一定数量的视频作为负样本。区别于word2vec的是,word2vec的负采样的优化方式是二元LR,而YoutubeNet中,采用交叉熵函数进行优化,正样本的label索引对应的才是1。
User Embedding就是DNN中最后一个ReLU(Dense)层的输出向量,其shape为[bs,emb_size],其中,bs是一个训练batch中的样本数。
我们知道,假设负采样10个样本,带上正样本1个,那么label一定是一个长度为11的one-hot。送给交叉熵的也一定是个长度为11的softmax函数计算后的向量。那么最后一个ReLU的输出,是如何计算得到这样的一个长度为11的向量呢?
论文中的图其实省略了一些东西,原论文中的softmax,其实是一个套上softmax函数的Embedding table(代码实现上,可以用全连接层,或者矩阵,或者nn.Embedding来实现)。下图可能更直观:
我们知道,user embedding的shape就是[bs,emb_size],其中bs是一个batch中user的个数(其实user embedding就是[1,emb_size])。而embedding table的shape是[emb_size,N],N就是上面说到的11,及多分类的类别总数。这个embedding table就是Item Embedding的table,它的每一列都是一个Item embedding。于是我们有[bs,emb_size] * [emb_size, N],得到[bs,N],参与到交叉熵的计算中。
原论文中的softmax是按照下面公式计算的:
其中,u矩阵就是user embedding矩阵,v矩阵就是item embedding矩阵,这样获取embedding的方式,和word2vec中embedding table的生成是一样的。
上图左上角是线上召回服务的方法。模型训练好后,Item Embedding就是一个Embedding table,将其存储到redis等数据库中。线上召回时,用户Embedding通过调用模型计算(最后一个ReLU的输出),实时返回用户Embedding;而Item Embedding则直接在数据库中调取(模型训练完后是个静态的embedding table)。
这里讲一下,上面讲的Embedding放到redis,只是存储方法。线上相似度检索并不是直接从几百万Embedding中计算相似度,一般都是基于ANN检索(近似最邻近检索),比如使用Facebook的向量检索工具Faiss,离线构建索引,然后计算每个用户最邻居的K个Item,最后再把每个用户最邻近的K个Item存储到redis中,线上直接查找K个结果就可以。
召回阶段已经给出了候选集,在排序阶段,其目的是对给定的小规模候选集进行精细化的排序。排序的基本框架和召回是类似的,需要重点关注模型的输入层和输出层,即排序模型的特征工程和优化目标。
排序的特征工程更为精细化,此处不做赘述,因为不同的业务场景下考虑的特征也会不同。这里重点关注输出层。负样本是有曝光无点击的视频,正样本是有曝光有点击的视频,预测用户的观看时长。正样本记录了用户观看视频的时长,为了预测观看时长,专门设计了一个加权逻辑回归模型(其实就是加权的二元交叉熵损失)。加入了观看时长这一衡量标准,也是为了用来解决噪声的,因为很多时候用户点击观看一个视频并不代表用户真的喜欢,满意这个内容。我们用观看时长对正样本做了加权,负样本都用单位权重(即不加权)。
至于线上serving的优化目标,这里直接贴上王喆书中的描述:
这里参照王喆的讨论
1. YouTube为什么不采取类似RNN的Sequence model,而是完全摒弃了用户观看历史的时序特征,把用户最近的浏览历史等同看待,这不会损失有效信息吗?
这个原因应该是YouTube工程师的“经验之谈”,如果过多考虑时序的影响,用户的推荐结果将过多受最近观看或搜索的一个视频的影响。YouTube给出一个例子,如果用户刚搜索过“tayer swift”,你就把用户主页的推荐结果大部分变成tayer swift有关的视频,这其实是非常差的体验。为了综合考虑之前多次搜索和观看的信息,YouTube丢掉了时序信息,讲用户近期的历史纪录等同看待。
但RNN到底适不适合next watch这一场景,其实还有待商榷,@严林大神在上篇文章的评论中已经提到,youtube已经上线了以RNN为基础的推荐模型, 参考论文如下: https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/46488.pdf
看来时隔两年,YouTube对于时序信息以及RNN模型有了更多的掌握和利用。
2. 在处理测试集的时候,YouTube为什么不采用经典的随机留一法(random holdout),而是一定要把用户最近的一次观看行为作为测试集?
只留最后一次观看行为做测试集主要是为了避免引入future information,产生与事实不符的数据穿越。
3. 在确定优化目标的时候,YouTube为什么不采用经典的CTR,或者播放率(Play Rate),而是采用了每次曝光预期播放时间(expected watch time per impression)作为优化目标?
这个问题从模型角度出发,是因为 watch time更能反应用户的真实兴趣,从商业模型角度出发,因为watch time越长,YouTube获得的广告收益越多。而且增加用户的watch time也更符合一个视频网站的长期利益和用户粘性。
4. 在进行video embedding的时候,为什么要直接把大量长尾的video直接用0向量代替?
这又是一次工程和算法的trade-off,把大量长尾的video截断掉,主要还是为了节省online serving中宝贵的内存资源。当然从模型角度讲,低频video的embedding的准确性不佳是另一个“截断掉也不那么可惜”的理由。
5. 为什么ranking model不采用经典的logistic regression当作输出层,而是采用了weighted logistic regression?
因为在第3问中,我们已经知道模型采用了expected watch time per impression作为优化目标,所以如果简单使用LR就无法引入正样本的watch time信息。因此采用weighted LR,将watch time作为正样本的weight,在线上serving中使用e(Wx+b)做预测可以直接得到expected watch time的近似,完美。
参考:
1.Deep Neural Networks for YouTube Recommendations
2.深入理解YouTube推荐系统算法
3. YouTube深度学习推荐系统的十大工程问题