本次分享主要包括以下几个部分:
1. 业务背景;
2. 召回相关技术与实践;
3. 排序相关技术与实践;
4. 思考及未来规划。
底层页指在点击左侧双列feed流中点击一个视频(1号)后继续滑动出现的视频(234号)
在底层页推荐场景中除了需要考虑和主视频的相关性以外,还需要考虑上下文(用户对视频234的行为)。
底层页的整体框架如上图所示,当客户端发起推荐列表请求,服务端会依次做以下事情:
请求画像服务,得到描述用户兴趣的特征;
请求Trigger,由若干个不同机制的Trigger分别得到不同的召回集;
合并召回结果,输入rank层做排序;
经过一些产品/业务策略的规则组成的曝光策略服务得到最终的视频list,发给用户。
服务的底层,直接和线上服务打交道的,包括做向量相似度计算的faiss,做缓存的redis,做消息队列的Hippo,还有一些数据分发服务。
再下面一层则是大数据计算平台Hadoop,Spark,SparkStreaming,以及机器学习计算平台Angel和Tensorflow。
召回策略主要分为以下4个方向:
基于热门:在冷启动阶段,缺少用户行为的时候,用高质量视频做推荐;
基于属性:根据年龄,性别,地域等用户属性,不同属性的用户有不同的兴趣偏好;
基于内容: 根据视频的标题,标签,图片等等,找相似的视频;
基于行为:根据用户的点击/播放行为序列,建模计算相关的视频。
ICF方法(基于物品的协同过滤)原理是比较两个视频观看过的用户列表,重合度越高则越相似。在计算协同过滤相似度时对原始公式做了以下优化:
考虑用户看两个视频相隔的时间,在分子上乘一个衰减系数,时间越长相关性越低;
考虑用户看视频的数量,在分母乘以衰减系数,对看大量视频的用户做降权;
不同的主item对应的其他item的list中分数的最大值可能差异很大,可以对每个主item做归一化处理。
表示学习的思路是类似word2vec,为每个样本(通过embedding)生成一个向量,再计算向量的相似度找到相似的样本。可以利用的数据例如视频封面,视频标题,视频标签和行为序列。
ImageEmbedding召回因为样本比较少,做分类模型困难,所以采用预训练的方法。加载Inception模型,输入图像做前向计算,将softmax前的输出层取出来即可得到一个embedding向量,最后使用faiss找到最相似的向量,也就找到了最相似的图片。评估目前采用人工的方法,人工评估召回的topN图片中有几个是相似的。
Title/Tag Embedding有两种方法:第一种是标准的word2vec模式,用自己的标题/标签数据训练一个词向量模型。这种方法的召回结果不太好,分析原因是数据量小。第二种是采用了公开词向量数据,这种用海量数据训练得到的预训练词向量模型,效果比第一种更好。
Network Embedding召回也叫Graph Embedding,有三种方式: 1. 矩阵分解: 效果不太好,用的比较少 2. 随机游走: 利用随机游走构造一些序列做embedding 3.具体使用中最直接的方法是:把用户的播放列表当作nlp中的一个句子(每个视频作为一个单词)训练word2vec。直接用word2vec会有一些问题,可以优化的方式包括:1. 对高低频的item(视频)做过滤和降采样 2. 合理的划分session(取多少天的数据)。
Network Embedding常见的做法并不是先将样本直接构造成skip-gram的形式,而是先把行为序列构造成图的形式,然后针对每个节点进行随机游走,生成一些候选序列,再去做Embedding学习。这样做存在的问题1:新的item缺少行为数据导致图稀疏,解决方案是将最近几个小时看的视频两两做全连接。问题2是热门视频:解决方案是对视频做聚类。
推荐系统的常规做法是分召回,排序两个阶段。原因是如果对全量数据(用户数*物品数)做排序,计算量可能太大,所以先用召回层减少候选集的大小。除非在某些特殊情况下,对全库做排序也许是可行的,如果物品的数量不是很大,比如只有几十/几百万,再把模型的特征减少。当候选池达到上亿甚至更多的时候就不可行了,尽管使用embedding方法可以近似选择全局最优,但是计算距离的方法比较单一。
高阶的方法是采用阿里提出的一种tree-based deep match的方法,核心的思想是要从全部候选池中找到用户感兴趣的item,为了减少问题的规模,将候选集构建成树结构,只有叶子节点才是单个的item,每个非叶子节点潜在表达了子孙items。
第一步:将视频按照二级分类排序,使得相同二级类目的视频处在相邻的位置,所有视频组成一个list。第二步:递归的将list一分为二得到左右子树,直到每个list只剩下一个或两个视频。这样就构建出了一个有层级结构的树。
将用户的历史行为序列和树中的目标节点做点积,经过深度神经网络之后得到用户对每个候选节点感兴趣的概率。
训练时正样本选择有播放行为的叶子结点和它的祖先。负样本有两种选择:(a)每层随机选择节点作为负样本,这样做的好处是结果的多样性好 (b)每层选择兄弟节点作为负样本,这样做的好处是和历史行为更匹配。完整的召回过程是自顶向下的依次对每个节点打分,选择topk,遇到叶子节点就放入召回池,遇到非叶子节点就继续向下寻找。
树形结构的好处除了可以做全库检索,还会有更好的多样性。这样做更符合人脑的特点,人通常不会只对某一种类别的内容感兴趣,而是对不同的内容都或多或少的有兴趣。
最后总结一下:最初级的方法是基于统计的协同过滤系列,之后演化出进阶的Embedding系列之所以应用比较广很大程度上受益于faiss提高了向量相似度计算的效率,目前最前沿的是TDM这种全库查询的方式。
接下来介绍排序模块,大致经历了LR,Deep,Wide\u0026amp;Deep三个阶段,其中LR模型暂时不做介绍。
深度模型目前采用了一种比较基础的架构。底层是sparse feature id。接下来embedding,每一列是一个field,比如画像信息、上下文等等。然后concat,经过全联接的隐藏层之后输出。DNN模型的效果与LR相比没有很大提升,原因是低阶特征组合能力不足,但好处在对稀疏特征的表达能力有提升。
Wide\u0026amp;Deep模型的Wide部分和LR的做法相同,所以克服了DNN模型的缺点,auc相对LR/DNN有1%的提升,不过依然依赖于人工做一些交叉特征。
Wide\u0026amp;DCN模型是2017年谷歌提出来的,它的特点是加入了一个cross层做特征交叉,具体的交叉方式如公式所示:每一层的Embedding由上一层和第0层交叉,每一层中的每个元素的交叉由阶数确定,最终形成了多阶交叉的效果。离线auc和W\u0026amp;D相比提高1%,而DeepFM和W\u0026amp;D相比提升不大。
最后在介绍一下工程方面的实践经验。排序的难点是要求实时,并且特征和样本的数量都很大。下面将会从样本数据,特征结构,离线训练,线上推断和模型调试五个方面分别介绍。
Tensorflow有两种处理特征的方式:明文vs二进制(TFRecord)。明文的特点是可读性好,但是速度慢。二进制虽然速度快,但也存在一些问题,只支持三种格式的数据,而且String结构比较占用空间,解析速度也慢。
特征结构尝试过三种方式。第一种是明文形式,FeatureColumn的速度非常慢,特征ID化方式比FeatureColumn快十倍,不论离线训练还是线上推断都是如此。后两种是特征ID的形式。
第一种是开放的特征id,使用方便,只需要把特征做hash,但缺点是Tensorflow底层dense结构无法支持。第二种是序列化特征id,这种做法的缺点是序列化速度慢,好处是可以做特征预处理。
离线训练使用的是数据分布式模式,数据并行计算梯度。模型是集中式的,非分布式存储,每片数据计算的梯度使用同步方式更新模型。
线上推断有两种方式。一种是TFServing,这种方式存在一些问题。因为加载模型和模型推断是采用同一个线程,所以在加载模型的时候会出现推断服务短暂阻塞,造成超时。TFServing还会定时自动加载目录中的模型文件,如果模型有问题也会自动加载模型,这是我们不希望发生的。另外在模型加载初期会出现响应慢的现象,通常称为WarmUp问题。不过可以通过BatchThread提升计算效率。
还有一种方式是用TensorflowAPI进行推断,可以自行设置触发条件控制模型的加载,而不限制于一定要固定的时间间隔加载一次。另外还可以自行调用session函数进行并行推断。
在提高模型的训练效率方面,有不少可以尝试的优化点,比如batchsize的调整,Tensorflow中dataset api中cache的使用,特征选择及Embedding调整,隐藏层个数及纬度的调整,样本降采样等等。使用Tensorflow timeline工具可以帮忙快速定位耗时函数,加速模型训练。
在提高模型的推断效率方面,可以优化线上特征数据拼接效率,及控制线程和batch之间的比例。
在提高效果方面,数据量越大越好,使用tensorboard关注实时auc和明文输出bias/loss等数据,尽早发现模型训练中的错误。
模型的演化过程大致经过了线性模型,非线性模型,兴趣模型这几个阶段。推荐和搜索业务的关注点是有一些不同的,推荐更关注对用户兴趣的描述,而搜索关注对query的理解。阿里的DIN和DIEN是大家公认对效果提升比较明显的。
最后是一些思考和未来的规划。Embedding方面计划讲将行为和内容融合到一起做embedding,还有一种方式将用户行为构建成图,利用图卷积神经网络做embedding学习。另一方面是序列化数据的利用,用LSTM/GRU做序列化的item推荐,或者直接对序列化行为建模用户兴趣,这些方法时间复杂度高,工程挑战较大。利用Bandit算法去做用户兴趣探索是常用的一种做法,后续将会探索强化学习尤其深度强化学习在兴趣探索上的应用。
此外两个难点,一个是多任务学习,因为有的时候任务目标不仅仅是点击率,还需要提高停留时长等指标。另一个是多模态,把图片和视频数据如何用到召回中来。
钱丁丁,腾讯高级研究员。Yoo视频底层页视频排序技术负责人,带领团队从0到1搭建短视频排序技术体系,并实现了从浅层机器学习模型到深度模型的升级换代。毕业之后加入搜狗商业部门,负责无线搜索广告的排序算法工作。曾在腾讯网络媒体事业部,负责天天快报新闻推荐系统排序算法工作。
本文来自钱丁丁在 DataFun 社区的演讲,由 DataFun 编辑整理。