作为一个推荐系统业余爱好者,在机器学习领域的鄙视链中,我感觉一直地位不高,时常被搞NLP CV语音等高科技技术的朋友鄙视。
最近甚至被人问,推荐算法开源包多如牛毛,我们为什么还要专门的推荐算法工程师?(难道想要辞退我!?惊)
不得不说,我想吐槽这个观点很久了。事实上搞推荐的工作不等于 import IBCF 或者 import time SVD++ import tensor啊摔!
于是找回帐号打开N年不用的博客,写一篇随想,其中含有大量主观臆断以及学术错误,尽量不中英夹杂术语之外的英文,如果有不同意见,欢迎回复指正。
说实在现在推荐包太多了,单机小规模实验的R包recommenderlab;慢的不行但是能够hadoop扩展的mahout;C++的eigen也给大家指明了一条矩阵运算的活路;matlab里各种memory based、model based、learning to rank算法包更是漫天飞;拿到风投的graphlab更是打出了号称五行代码动手写推荐系统的口号,还附带各种FM模型以及一健运行deep learning的套餐供大家玩耍;想要自己感受DIY的快乐,还有libFM;嫌慢可以使用SVDfeature简化套餐,还支持多线程硬盘计算,2G笔记本就可以建模2T数据。
(五行实现一个推荐系统,你怕不怕)
那做一个推荐系统,看来确实不需要专门的推荐算法工程师了,import xx即可。
事实上并不是这样,其问题在于几个方面:1.业务转化数学问题 2.数据特性定义active function 3.根据业务定义合理损失函数 4.损失函数求解调优 5.计算量太大的离线算法优化和线上算法优化。
我们可以看到,一个完整的推荐系统项目不能靠import xx实现的至少有上述几点。能够把这5点走通玩好,才是老板养这样几个工资万儿八千天天看起来成天只会看动画无所事事的推荐算法工程师的原因。
1.业务转化数学问题
一般一个项目启动都是老板说,我们公司的现在电话销售(app下载、商品销售、淘宝客收入等等)挺不错的,但是推荐栏的那个IBCF算法太搓,或者人工运营太累,你们能不能搞个推荐提高下转化率?
和做学术以及竞赛不一样,我们并不知道有哪些数据,也不知道要做成什么形式,推荐位放在哪,UI怎么搞比较好,这些都是需要和业务方一起磋商定稿的。
以电话销售为例,我们需要给电话销售人员一个列表,告诉他你今天给这样几个人推销这样几个商品会比较好。然后开工了,我们需要跟业务人员在一起商量,到底用什么数据能够完整的体现一个销售人员给特定的客户推销什么商品会成功?以此为依据决定收集什么样的数据,而非一般书籍里讲述的,仅仅使用用户商品矩阵这么清爽明快的事情。
以这个特定问题为例,我们需要的是销售人员数据,用户数据,商品数据,用户商品交互数据,销售人员商品交互数据,销售人员用户交互数据。其中用户商品交互数据中的很小一块便是很多开源包可用的UI矩阵。
数据收集来了之后对数据做统计,消除特殊活动以及广告引流等影响,搞定缺失值、默认值、异常值等问题。里面还经常会遇到一些机器学习的子问题要处理,比如垃圾用户怎么排除(基于强规则弱规则构造特征做一个小分类器之类的)。
填完这些坑,往往半个月一个月过去了,还非常辛苦(我的感觉是:程序员来自地球,业务人员来自火星)。。。。
2.数据特性定义active function
继续拿上面那个问题说事,数据清洗好该构造特征定义active function了。
active function是我随便叫的,或者叫model equation?总之我们如果假设特征相互独立,那么就是 y=wx 这种;如果认为特征集之间会有交互,我们有两种方法,第一种是做一个 low rank 假设,比如 SVD 的 y=pq这种形式,就是对于用户商品交互特征进行建模;另外一种就是写成y=wij*xi*xj这种形式。前面一种是 factorization models 的搞法,后面一种是 用rf或者gbrt的交叉特征的搞法。
对于我们这个问题来看,销售人员特征、用户特征、商品特征这种就属于wx这种形式;而销售人员商品交互特征、用户商品交互特征、销售人员用户交互特征这种就属于y=sq+sp+pq(销售s,用户p,商品q)这种形式。
所以整体来看我们问题的定义下来,active function应该为y = wx + sq + sp + pq的形式。顺便一说,考虑到时间因素,还要再加上好几个t的项(如果采用pairwise interaction tensor的形式的话)。
定义好形式就可以抽取特征了,然后按照 categorical variables以及noncategorical variables的形式整理好,这时候就可以开心用包啦!
打个比方,libFM就提供了一个建模的通用式子
分别是bias,独立特征以及交互特征,一般人常说的IBCF,SVD等都是这个式子的特殊形式而已。
顺便这里说下,现在搞推荐的,一般两种流派,一种是用MF的,一种是用LR,RF,GBRT上高维特征的,经常吵的劝都劝不动。
我觉得这个只是数据特性的两种active function定义的倾向而已。
前者考虑到不同categorical variable的交互。对于wij,我们经常是很难观测到行为的,比如用户i给电影j的行为,已经观测到才能估计wij,但是这表示他已经看了电影了,那推电影j就没意义了,所以我们使用pi*qj来近似wij。
后者一般不考虑categorical variable的交互,或者他们能观测到wij对应的xi*xj的行为,所以直接用分类回归模型求解wij而无需使用low rank假设。比如说天猫商品推荐,用户想买一个商品,经常会有点击搜索行为,这种xi*xj就是可观测的了,所以直接上rf或者gbrt就是合理的。其active function的通式为这个:
所以一句话,没有所谓推荐算法哪家强,只有合适的应用场景对应的合适的active function,然后影响到我们是用MF还是LR RF这种。观测不到或者观测很少用前者,反之用后者。或者两个都上,做ensamble(有计算资源,就是这么任性)。
3.根据业务定义合理损失函数
这又是一个比较有争议的话题,不过也是推荐从业人员的工作核心所在,大概要忙活一下午?
一般的损失函数有三种,1.回归 2.分类 3.排序
比如说:,
说实在,我干活从来不用前面那种,只有竞赛明确指明排行榜按照RMSE排序才会用前者。因为我们经常要做的是top-N的排序,对于用户给商品打分估计准了,但是转化率提不上去没用,因为用户只考虑买还是不买,很多研究也指出RMSE跟转化率和top-N不是很搭。
说到损失函数不得不说最近很火的learning to rank,其损失函数是MRR这种直接优化排序的,相比AUC等考虑全局排序或者甚至只是point wise的分类系列损失函数,从理论上来说更加合理。其损失函数是个非凸损失函数,我们一般把其近似为凸函数求解(实际上还是有点坑)。
然后我们要考虑损失函数是否带权,以及正则的问题。带权主要是比如一个商品推成功了赚5毛,一个商品推成功了赚50,天壤之别,这就要结合业务来定义了。正则一般上L2,比如这种
另外很多人觉得损失函数定义成怎样对结果影响不大,我觉得吧,还是很有影响的吧摔。
4.损失函数求解调优
在给定对数据的观测下定义优化问题求解优化问题一直是机器学习的主旋律,俗话说,数据挖坑一身功力全在调优(并不是)。
我们一般要选择一个科学的适合现状的方法,还有搞好超参数。
拿常用的推荐系统优化方法来说,SGD,ALS以及MCMC一般的算法包都会提供。以LibFM为例对比三种方法:
可以看到,新手用MCMC inference最好。在推荐的问题中,一般只需要调两个超参数就好,factor的dimension k以及对factor初始化的高斯分布的std。k一般从小的着手,5啊8啊都是不错的做第一次调参的选择,太大容易过拟合。std对结果影响很大。不过好在也比较好调,一般选择0.1 0.2 0.5 1.0这种,而且我们一般在迭代的初期就可以通过观测training error的方式就可以确定了,甚至比常用的开源包的实现方式(从train里抠一部分做holdout set做观测)还好。
如果是高手,可以挑战SGD,SGD的参数除了MCMC的那几个,还有几个非常不好调的参数,有正则项的lambda以及学习速率。正则项没办法,只能靠grid search。学习速率更坑,高了不收敛,低了跑的慢,具体什么速率好只有上帝知道。(最好是0.0127这种,不要是10的倍数,我瞎说的)。
总之,这块也是一个具有挑战性和技术性的不能自动化的工作。
5.计算量太大的离线算法优化和线上算法优化
算法一般分好几个部分,一般有线下部分和线上部分,比如很多做法是线下选离线商品池子,线上CTR预估。这样就涉及到大量的离线评测和线上算法架构。
一般的公司项目的数据量都是单节点运算支撑不起的。百万级有行为用户和几十万的商品都是很常见的,小规模也有几万,所以要离线评测一般需要并行和分布式。这些也是很难自动化的。
对于数据的预处理和特征的构造,一般都是数据并行,规模不是特别大的log或者不是太多冗余的文本,python脚本nohup也是个不错的选择,或者用hadoop写MR。模型的算法并行看情况,一般的MF类型模型可以O(kN)求解,单机写的性能高点小时级别还是可以出结果的(比如SVDfeature这种),或者公司有条件上MPI,自己写spark也可以,但是没有看到成熟的成功案例?还有用graphlab这种性能也是不错的。
线上的话架构等模型定下来做LR这种,有实时的特征(最近30个点击这种),也有离线算好的,一般会对用户大体离线算个离线池子,这样线上压力小,storm都是不错的选择,反正不需要实时训练,数据增量记录好一天甚至一周一迭代就好。
当然要上线要经历九九八十一难,某厂一个产品离线到AB test上线到最后,存活率不足1%,还要根据线上结果咔嚓掉一半,这些也是工程师要经历的磨难。
所以说了这么多,就是说,报告老板,当推荐算法开源包多如牛毛,我们还要专门的推荐算法工程师的!有好多事情可做的!(于是我的饭碗保住了,又可以愉快看动画片在B站自由飞翔了)
很多地方写了后面忘记前面,大家有什么想法快来交流,相互提高,邮件交流(我近期兴趣点在于如何有效利用外源数据提高推荐效果以及learning to rank调优这块) flclain@gmail.com