Fork me on GitHub

洋码头推荐系统重排算法实践

作者介绍
马超群, 洋码头高级算法工程师
具有多年数据挖掘、算法、机器学习的研究与实践经验,负责洋码头推荐等系统的算法研究与开发。


传送门: http://www.6aiq.com/article/1537369469861

本文约4500字,可参阅下面的大纲阅读。

1. 第一阶段

2. 第二阶段

3. 第三阶段

4. 算法模型实践小结

5. 关于未来

6. 参考文献

 

2016年之前,洋码头的推荐系统主要还是聚焦于基于用户画像的推荐、协同过滤的推荐等入门级的玩法,重点还是基础数据的完善。  2016年初,洋码头开始引入更复杂的算法模型。本文重点说一说重排模型。

所谓重排算法模型做的事情就是:为每个用户对召回阶段得到的商品候选集的所有商品打分并进行重新排序。

 

洋码头推荐系统中的重排算法模型是随着业务发展不断迭代的,我们的迭代主要分为三个阶段。

 

1. 第一阶段

时间段: 2016年初 - 2017年中

因为前期基于规则和一些分数加权的排名在影响因素很多的时候不够精准,我们决定研发和上线一个更专业的模型在重排阶段进行精准排名,这也是业界通用的做法。首选的模型是过去几年里在业界非常流行的GBDT树模型。

树模型的好处是可以自己去做特征的组合,把不同的特征放在同一棵树下,并且多棵树模型在过拟合问题上表现比较好。

特征上主要是用户画像的特征、商品画像的特征及商品统计的特征。

样本构成:,Label是1或0表示你是否会点击或购买某一商品。

我们设计了一套编码规范和特征映射关系表,称为FeatureMap。基于FeatureMap,结合模型训练的结果,可以把模型的权重及重要度进行分组统计并可视化出来,更重要的是它可以辅助定位特征工程数据的问题。

这个FeatureMap在前期出现了很多问题,因为特征工程较复杂:有几十个数据源,要构造不同时间窗口的画像,且编码处理复杂。这个时期我们经常查看和分析这个FeatureMap与模型结果,然后查看哪些特征真正学出来了,哪些学习得比较好,然后对特征工程进行针对性优化。同时GBDT输出的叶子节点对应的树上的隐式特征组合我们也拎出来,查看算法决定的组合跟先验设计的组合有什么差别,最后回馈到特征工程上去,决定是否做些显式的特征交叉与组合。

在解决了许多特征工程上的bug和数据问题后,发现有些特征学得还是不够好或者因为特征太稀疏了,学不出来。

阶段成果: 我们把GBDT树模型应用在了商品主题清单列表页[必买清单栏位]的推荐的召回部分;而重排算法经过短暂的测试后并没有深入应用,没有达到预期目标。

2. 第二阶段

时间段: 2017年中 - 2017年底

这个阶段的小目标是上线逻辑回归[LR=Logistic Regression]模型。

因为上一个版本GBDT存在一些问题,我们要继续优化算法模型。其中包括继续优化特征工程,并尝试转向LR模型。

上一阶段的工作为特征工程打下了不错的基础,LR与GBDT  底层的特征工程数据源也都是相同的,因此不需要完全重做特征工程。尝试LR模型过程中有一个核心的点是LR要做用户特征和商品特征的Match,称之为Join型特征。解释一下就是说,一个用户在过去的APP中的浏览记录中对一个商品有一个历史行为这个事实由一个特征来表示,构成一个<用户,商品>的Join型特征。

样本构成:。

最终特征空间的维度约到达400万左右,重点还是品牌类目、核心词等用户画像和商品画像中的常见特征并结合多维的时间窗口进行了扩展。我们的特征混合了几种类型,二值型特征、类别特征、连续值特征都有。

 

回到LR模型,它的解释性强,因为每一个特征都对应一个权重。我们自定义了一些特征重要度的指标,计算维度包括模型的特征权重和特征出现次数等。结合FeatureMap,我们可以按特征类型、时间维度等不断细分查看特征重要度。经过测试,最终选用了L1正则稀疏后生成的拥有几万到几十万的特征的模型用于线上部署。在特征选择上综合了基于人工经验、基于模型、基于线上视觉测试等多种特征选择方式。

不同的特征具有不同的。总体上看,主要是商品的统计类特征和Join型特征在起作用,前者在AUC的贡献上是巨大的,后者表达个性化。翻译一下就是我们会给客户推荐卖得好同时又是其感兴趣的商品。

阶段成果:  模型成功在必买清单栏位上线,对点击率、转化率的提升超过50%。

3. 第三阶段

时间段: 2017年底 - 至今

这个阶段的目标就是不断优化模型与系统,迭代特征工程与算法模型的版本,将模型全方位应用于各种栏位和场景中,并持续AB测试。

这里会综合说一下特征工程、算法实验、模型训练、工程优化等几个方面的实践,这些都是跟算法实践紧密结合在一起的,整个算法实践完全不是推个公式,写个算法,然后跑一下这么回事情。

3.1 关于特征工程

特征升级到了千万规模,编码体系做了一次改造,特征Id使用了Long型编码。特征工程版本上增加了特征Hash。

优化特征工程,解决模型上线上后遇到的实际问题,比如商品季节性问题。

长期画像增加时间衰减,用户行为次数更换成行为天数,增加不同页面的样本等等。

优化一些特征处理的细节,特征平滑、置信度等。

我们按不同的场景进行样本的选择和特征的选择,构造了不同的模型,有的偏转化、有的偏点击、有的偏广告数据等等。

尝试过把商品ID类特征加进去,效果并不是太好。

3.2 关于算法实验

在离线算法实验上我们也有丰富的实践:

首先是跟进早期Facebook的做法,尝试GBDT和LR的两个模型的融合。融合通常有几种方式,较简单的是几个模型得分的Average,还有就是把GBDT模型产生的一些结果和特征作为LR模型的训练特征。从实验结果上看,离线效果上均有明显提升。特别地,在我们的场景中,GBDT对于几千个核心特征的效果非常好,并且它们是AUC贡献最大的部分,而LR则强化了更多稀疏的特征的学习。

在LR模型效果相对稳定后,我们开始尝试点击率预估的一些其他常见的进阶算法模型,比如FM[Factorization Machine]和FFM[FieldawareFactorization Machine]。从原理上来讲,LR是人工有限特征组合,而FM则是自动特征组合。从实验结果看,FFM的离线效果确实更好,而FFM则是把特征的类别[Field]这一信息考虑进去了,学习到的隐向量不仅与特征有关,也与Field有关。事实上,在我们的LR的特征工程中也有考虑到利用这个信息,并且这是一个核心要点。

经过努力我们把FFM上线了,发现线上效果并没有比LR好多少,这是个头疼的问题。最后FFM+LR进行Ensemble才在线上指标上有所提升。FFM和LR模型的预测分数的分布曲线的形态完全不同,前者较均匀,后者较钟形或右偏峰[加权训练时右偏峰],具有互补的效果。线上效果不好可能的一个原因是我们缩减了一些特征,包含一些稀疏特征(我们的特征空间太大,当时单机训练有性能问题)导致有些精度上的损失,而FM又针对稀疏特征的组合上效果好。

随后尝试了DeepFM,效果有非常大的提升,是当时离线效果最好的。但是因为我们当时在Tensorflow的模型上线上积累还不够,因此转向尝试其他几个算法,如MLR和FTRL。MLR是参照阿里的文章,同期对比了一个FTRL的版本。经过测试,发现MLR离线效果跟DeepFM相当,FTRL离线效果只比LR略好,但FTRL不断更新线上模型特征,潜力不错。经过努力,最终MLR和FTRL都成功上线,不过提升并没有前期那么大,只有百分之几的提升,并且有所波动。我们也发现FTRL产出的模型有一个问题就是学习出来的特征的权重的值太小了(大部分都是0.00x),包括我们用Keras上试验也有类似问题。这跟XGBoost的GBLinear方法学到的权重有巨大的差异。

 

3.3 关于工程优化

主要是特征工程的优化和模型上线的优化。

模型训练出来后,要线上调用,我们线上逻辑和业务代码主要使用Java开发,但是模型训练有各种语言和框架,以C和Python居多,并且模型格式也各不相同,所以首先要解决和现有的技术栈的兼容问题。

前期LR和GBDT的模型我们主要使用JNI调用的方式。后期,对于某几类常用的模型,我们使用Java自己去解析模型文件格式并实现预测,这样的做法会使得线上模型部署代码更统一。而像LR这种模型的预测本身并没有什么难度,就是一个线性加权计算。难点还是特征编码以及线上预测时拼接特征这一块,即有复杂度也有性能上的消耗。并且如果同时上线两个版本的特征编码不同的模型,特征还得存两份。

MLR和FFM是C++版本,上线前改造了一下,并使用了SSE指令集加速等策略。

3.4 关于模型训练

我们之前是隔一段时间更新一下模型,比如一个月更新一次模型。后来自动化了之后,可以每天每小时更新模型。

原始的训练方式是下载数据,加载到内存,进行模型训练。之前有一个问题就是每次从HDFS[集群文件系统]下载数据,下载个50G-100G到训练机器时过于麻烦。因为同时会训练有6个模型,那么下载600G的数据的时间开销可以想像。因此改造成直接读取HDFS数据进行流式训练模型的方式,效率上提高许多。

在训练方式与工具选择上,主要是单机训练结合分布式训练。

原则上单机能搞定的就单机搞定,单机搞不定的就分布式训练。我们的实践经验是分布式训练上会有精度损失,学不到单机的效果,并且调参的时间成本也大一些。有一个方式弥补:增加样本量。因为单机没办法训练海量的数据,而分Batch增量学习的方式许多时候效果并不好,特别是数据跨了许多天、一个月甚至几个月的时候。

值得一提的是XGBoost的样本加权训练模型的效果比较好。因为我们的样本构造时有不平衡的情况,本身用户加购、支付等行为的样本是较少的,而点击、曝光等行为样本较多,因此设置了不同的权重。

 

4. 算法模型实践小结

1. 算法的版本规划上要考虑基础设施和基础数据及资源的限制。

  • 基础设施指的是集群环境,在我们阶段1的时候,特征工程上,特征是离线的,小时级的特征,到了阶段3,引入了SparkStreaming,加入了实时特征。

  • 基础数据的完善主要是阶段3中一些特征的丰富度和细粒度,比如商品相似的特征和聚类的特征等,因为做数据要花时间,同时完成一个事情有多个方向,一般都会在各种方面达到60分后,再优化到80分,而不会在一开始就追求各方面都达到80分。。

  • 资源限制一个是机器资源,一个是人力成本。机器资源比如计算资源,公司的计算资源都是按时间规划采购,对于大的集群资源,可能一整年中都是这个情况。人力资源的重要性当然是不言而喻的,有时机器资源丰富,不用去优化代码。而有时有核心性能问题,比如计算太慢,达不到预期,必须要人去花时间优化代码。

 

2. 在资源有限的情况下, 做算法模型选型时要聚焦。在我们的重排序模型中,主线是CTR预估的二分类模型的特征工程方案,包括GBDT、LR、FTRL、FM、FFM等总体的特征编码都是一样的。整个开发实现及优化过程历时会很长。为了聚焦,我们并没有过多地在重排模型中尝试别的算法选型,比如ALS、SVD++等其他推荐算法方案。

 

3. 在实践中,经过长时间优化特征工程和几十次模型训练后,效果依然不好,就很容易导致项目达到被放弃的边缘。我们的经验是在正确的道路上坚持到底,或者在统一的正确框架下多多尝试,不断细化实践中的一些细节,分析指标、定位问题,一定是能搞出效果来的。

 

4. 算法实践上,要注重团队协作,有阻塞的地方要及时暴露出来及时解决。

 

5. 关于未来

还是紧跟业界主流的方式,不断优化,比如工程上增加ParameterServer,算法上探索更多DNN的广泛应用,如基于Session的RNN、实时意图识别、DIN等等。

 

6.参考文献

下面是写作这此文的时候参考的几篇文章,对推荐系统算法相关感兴趣的同学可以综合参考一下。本文重点并不是算法上的一些细节,而是大概做了哪些事情和要点,有些GBDT+LR的数学公式及细节等,可以参考文2。

  1. http://36kr.com/p/5114077.html

  2. http://www.sohu.com/a/217734902_488163

  3. https://yq.aliyun.com/articles/68805

  4. https://zhuanlan.zhihu.com/p/32785759

全文完


本文地址:https://www.6aiq.com/article/1537369562943
本文版权归作者和AIQ共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出