缺人缺钱缺资源的小团队,如何搭建电商智能推荐机器学习系统
导读
导读:为了提高当当推荐/广告模块的点击/转化率,提升用户体验,同时也为了提升当当推荐/广告模块的智能化程度,加强对大数据的分析加工能力,当当推荐组从2014年开始搭建机器学习系统。
本案例介绍了当当推荐团队构建机器学习系统的实践过程、工程方法、经验教训以及总结和反思。还针对非BAT级别的小团队在系统构建中的挑战与优势进行了整理与分析。
(全文共8173字 预计阅读时长:8分钟)
一、案例特点
本案例介绍了当当推荐团队构建机器学习系统的实践过程、工程方法、经验教训以及总结和反思。
本案例具有以下3个特点:
“面向过程”,希望重点分享系统构建的过程、方法以及经验教训;
“面向系统”,在关注机器学习模型的同时,本案例更加关注从整体角度看系统;
“面向小团队”,出于我们团队的自身情况,以及行业的一些现实情况,本案例会针对小团队的实践做一些分享和讨论。
二、案例背景
为了提升大数据处理分析以及挖掘能力,并将其用于推荐、广告等重要的大数据产品上,提高点击、购买,提升用户体验,当当推荐团队从零开始搭建了一套完整的机器学习系统。
由于是从零开始搭建,我们在此过程中,在模型训练、样本工程、特征工程、工具方法、开发流程、系统架构等方面都经历了很多曲折,也从中收获了很多经验教训,并且将这些经验应用到了系统的持续改进提升上。
本案例从系统构建过程为切入点和视角,展示了我们的系统构建方法、流程和工具方法,因为我们认为好的系统是在合理方法的指导下通过不断迭代方能得到的。
我们还会从整体系统的角度分享一些我们踩过的“坑”,旨在指出系统构建的一些关键点,这些关键点不仅涉及到学习模型这一系统的核心,还会涉及到系统中其他的关键部分。
由于现在机器学习的应用非常广泛,而由于多种原因,大部分公司的机器学习团队都无法达到BAT那样的级别,所以在分享系统本身之外,本案例还会针对小团队在构建机器学习系统中遇到的挑战和优势进行讨论,希望能为广大从业者提供一些有用的参考。
该系统目前用于推荐模块的排序和广告模块的排序。
在推荐模块上取得了首屏点击率提升15%~20%;
在广告上取得了点击率提升30%;
RPM提升20%的效果。
总体来看起到了良好的效果。
三、简述小团队
为什么会出现小团队?这个问题乍一看有点像是句废话,因为每个团队都是从小到大发展起来的。
● 3.1 机器学习团队的特点
相比一些功能性系统,机器学习系统的特点之一是不确定性,也就是这个系统搭起来的效果,是无法从项目初始就量化的。这导致决策时在投入上比较谨慎,不会在刚开始就投入太多人力和资源。
这方面人才确实比较稀缺,招聘难。尤其是有实际能力或经验的其实很少。本着宁缺毋滥的原则,小而精的团队是一个更好的选择。
● 3.2 小团队做系统的挑战
这是我们关心的首要问题。小团队挑战的本质在于人少。从这个根本限制会衍生出多个具体的挑战。
对单兵能力的高要求
人少意味着每个人都需要发挥很大的作用,因此对单兵能力要求比较高。对于这个问题,主要就是外部招聘和内部培养来解决。
同时负责多个任务,协作要求高
在系统开发过程中,大家一般都需要交叉负责多个任务,这既是对个人能力的挑战,也是对协作能力的挑战。但是另一方面,这其实是对员工最好的培养,能够让大家以最快的速度成长。
方向和需求选择的问题
因为人少,所以在决定下一步行动时,需要非常谨慎,尽量减少无产出的投入。这有时确实是一种限制,但是换个角度来看,这“逼迫”我们把精力集中在最重要的部分,好钢都使用在刀刃上。
单点风险较高
由于每个人都负责了比较多的部分,所以每个人的离职、休假等异动,都会对系统造成较大影响。这个问题同样主要是通过内部培养和外部招聘来解决,不过还有一个方法,就是用有挑战的事情留住人。哪种方法更管用,就要看具体环境的具体情况了。
● 3.3 小团队的优势
小团队易于凝聚。这也是小团队的天然优势。
易于协作。很多事情不需要开会,转身几句话就可以搞定。
迭代速度的优势。由于流程所涉及的事情全部由少数几个人负责,不需要协调过多的资源,那么只要这几个人使劲,迭代速度就会快起来。
非常重要的一点,就是团队的成长。由于大家都要负责很多事情,那么成长速度自然就会很快,同时个人的成就感也会比较高,如果调配得当,会让整个团队处于一种非常有活力的积极状态。
四、推荐系统架构
在介绍我们的机器学习系统之前,先简单介绍一下我们推荐后台(不包括前台展现)的整体架构,以及机器学习系统在其中的位置和作用。
图1所示的是我们推荐后台的整体架构。从架构简图中可以看出,机器学习系统是作为一个子系统存在的,与推荐作业平台(生成推荐结果的离线作业平台)发生直接互动。
图1 推荐后台的整体架构
在图2中的架构图是图1中部分细节的放大。从图中可以看出,机器学习系统是在结果排序中发挥作用的。
图2 推荐平台作业和机器学习系统架构图
在图3中的架构图是图2架构中部分内容的进一步展开,也就是机器学习系统本身的一个架构简图。有经验的同学能看出来,这张简图中包括了机器学习系统的主要流程部件。
图3 机器学习架构简图
五、 系统构建
下面介绍我们的系统构建流程。
● 5.1 初期探索
系统初始阶段,是一个探索的阶段。这个阶段的意义在于,搞明白要处理的问题究竟是不是一个适合用机器学习技术解决的问题,以及当前拥有的数据是否能够支持机器学习系统。
机器学习系统应用面很广,但不是万能的,尤其是某些需要强人工试验的领域,可能不是最合适的方案,尤其不适合作为系统启动的方案。
在这个探索阶段,我们使用的工具是R和Python。
选择R的理由
因为R的全能性,堪称数据科学界的瑞士军刀。
因为R已经流行很多年了,属于成熟的工具,遇到问题容易找到解决方案。
当时(2013年)sklearn之类的还不够完善好用,而且有问题也不容易找到解决方案。
选择Python的理由
Python的开发效率高,适合快速开发、迭代,当然要注意工程质量。
Python的文本处理能力较强,适合处理文本相关的特征。
Python和Hadoop以及Spark等计算平台的结合能力较强,在数据量扩张时具有可扩展性。
不过,R的部分其实也可以用Python来替代,因为以sklearn,Pandas,Theano等为代表的工具包都已经更加成熟。
● 5.2 典型开发流程
当过了初期探索的阶段,到了大数据量的系统时,R就不再适合了。主要原因就是两个:可处理数据量小和处理速度慢。
第一个是因为单纯的R在计算时只支持单机,并且数据必须全部载入内存,这显然对于大数据处理是个很明显的障碍,不过现在的一些新技术对这一问题或许会有所缓解,但是我们没有尝试过。
其次就是计算速度相对慢,这当然指的也是在大数据量下的速度。
所以,一旦到了大数据量阶段,以Hadoop和Spark为代表的工具就会登上舞台,成为主要使用的工具。
过了初期探索、验证的阶段后,就要进入工程迭代的步骤了。如图4所示的是我们开发的一个典型流程。
图4 典型开发流程
验证通过之后,就进入下一个重要环节,我称之为“全流程构建”,指的是将要构建的机器学习系统,以及后面的使用方,全部构建起来,形成一个完整的开发环境。
这里需要强调的是“完整”,也就是不只是要搭建起ML模型相关的样本、特征、训练等环节,后面使用模型的环节,例如排序展示等,也要一同搭建起来。关于这一点在后面还会再次提到。如果是初次构建系统,那么“全流程构建”将会花费比较长的时间完成。但这一步是后面所有工作的基石,投入的时间和精力都是值得的。
这个步骤完成之后,一个系统其实就已经构建好了 ,当然是一个只有形没有神的系统,因为每个部分可能都是完全未优化的,而且有的部分可能是只有躯壳没有内容。
之后就进入优化迭代部分,这部分的工作就是不断寻找可以优化的点,然后尝试各种解决方案,做线下验证,如何觉得达到上线标准,就做线上 AB。在系统流程构建起来之后,后面基本上就是不停的在这个迭代中轮回。如图5所示。
图5 开发流程中的优化迭代
其实这个开发流程,特别像盖房子的流程,先要打地基,之后建一个毛坯房,之后就是不断装修,各种验工,直到可以入住。住进去一段时间可能觉得那里又不满意了,或者又出现了什么新的、更漂亮的装修方法,那可能又会再次装修。如此反复。直到有一天你发财了,要换房子了,那也就是系统整体重构、升级的时候了。
我们在构建系统中使用的工具,都是一些市面上常见的主流工具,除了dmilch这套工具。构建系统的工具如图6所示。
图6 构建系统的工具
dmilch(milch 为德语牛奶的意思):Dangdang MachIne Learning toolCHain是我们在不断迭代中总结提取出的一套特征工程相关的工具。包含了一些特征处理的常用工具,例如特征正则化、归一化,常用指标计算等。和 linkedin前段时间开源出来的FeatureFu目的类似,都是为了方便特征处理,但是角度不同。
● 5.3 项目推进
接下来介绍几个我们在工作流程中的关键点。
中心思想:小步快跑,发现小团队优势。
改动之间尽量串行,以确定真实影响因素。
每周一到两次会议讨论,当场确定下一步动作和时间。
工作有分工,讨论无分工。
其实小团队在这个方面是有着天然优势的,所以我们的中心思想就是“小步快跑”。
第一个关键点就是改动之间的串行性。这或许是机器学习这种算法类系统的独有特点,多个改进一起上的话,有时就无法区分究竟是什么因素起到了真正的作用,就像一服中药一样,不知道起效用的是什么药材,而我们希望的是能把真正的“青蒿素”提取出来。
第二个关键点就是项目推进机制。我们大概每周会有一到两次的会议讨论,主要内容是验证改进效果,方案讨论等,并当场确认下一步的动作。
技术人员其实是不喜欢开会的,那为什么每周还有开呢?我认为最重要的一个目的就是让大家参与讨论,共同对项目负责,共同成长。承担的工作有分工,但是在讨论时无分工,每个人都要对系统有想法,有建议。这也能确保大家互相吸收自己不熟悉的地方,更有利于成长。
● 5.4 新技术尝试
新技术尝试是一个很有意思的话题。如果沿用我们之前的盖房子的例子,新技术就好比高大上的家具摆设之类的,家里没个一两件镇宅的,都不好意思跟人打招呼。
这方面我们的经验是,先把已有的技术吃透、用透,再说新技术不迟。例如推荐中的协同过滤算法,一般会在购买、浏览、评论、收藏等不同数据,不同维度都去加以计算,看哪个效果更好。当把熟悉的技术价值都“榨取”干了之后,再尝试新技术也不迟。
还有一点很重要,就是别人的技术,未必适合你。不同公司的业务场景,数据规模,数据特点都不尽相同,对于他人提出的新技术,要慎重采纳。
我们曾经满怀信心地尝试过某国际大厂的某技术,但是反复尝试都没有得到好的效果,反而徒增了很大的复杂性。
后来和一些同行交流之后发现大家也都没有得到好的效果。所以外国的月亮,有可能只是在外国比较圆。上什么技术,还是要看自己系统所在的土壤适合长什么样的苗。
六、关键经验教训
“前事不忘,后事之师”,我们在构建系统过程中积累了很多宝贵的经验和教训,在这里介绍几个我认为比较重要且关键的经验教训。
● 6.1 只见模型,不见系统
如果要把我们经历过的教训排个名,这个教训一定是第一名。
具体来说,这个问题指的是在构建系统时,我们一开始基本只关注机器学习模型的好坏,AUC如何,NE如何,但是没有关注这个模型到了线上的最终效果是如何的。
这样做的后果是,我们觉得模型从指标等各方面来看已经非常好了,但是一上线发现完全没有效果。因为我们忽略了模型是被如何使用的,一直在闭门造车一样地“优化”模型,最后的效果自然不会好。
那正确的方法是怎样的呢?
从我们的经验来看,在系统搭建的初期,就要明确地知道:你构建的不是一个模型,而是一个以模型为中心的系统。时刻要知道模型构建出来之后要干什么,要怎么用,这种大局观非常重要。模型虽然是系统的中心,但不是系统的全部。在系统设计、开发、调优的各个阶段,都要从系统的角度去看问题,不能眼里只有模型,没有系统(产品)。否则可能等你调出一个AUC=0.99模型的时候,一抬头发现已经离系统越走越远了。
所以,做机器学习系统要注意模型和系统并重,如果只看到模型而看不到系统,很可能会做出指标漂亮但是没有实效的“花瓶系统”来。
● 6.2 不重视可视化分析工具
这是一个开始很容易被忽视,但是到后期会导致你很难受的一个问题。
因为机器学习系统某种程度上是个黑盒子,所以我们的精力会习惯性地集中在参数、模型这些东西上,本能地觉得模型的内部工作是不需要关心的。但是我们的经验是,如果只关注黑盒子的外面,完全不关心里面,那么如果模型效果不好,那么将很难定位到问题的所在。
在这个问题上我们的感触是很深的。我们最早在做系统的时候,发现效果不好,其实是没有太多章法能够帮助定位问题的。只能是把各种特征来回特征,样本处理上变一下花样,如果效果好了,就好了,不好,接着折腾。
直到我们做了一套Web页面,上面把每条样本、每个case的特征及其参数,样本的出现次数,在候选集里的排序,等等,全部展示出来。如同把整个系统加模型给做了一次解剖,希望能够尽量多地看到系统的内部细节,对于分析问题有很大帮助。
这个系统帮了我们很大的忙,虽然也不能算是完全“有章法”的做法,但是把很多东西呈现在你面前之后,你会发现有些东西和你想的不一样,也会发现一些你压根不会想到的东西。这对于机器学习系统这种有点像黑盒子的系统来说,尤为宝贵。到现在,这个系统是我们每次效果验证时非常依赖的一个东西,可以说是我们的另一双眼睛。
●6.3 样本想当然
众所周知,样本是机器学习系统中很重要的一部分,正样本和负样本的选择都需要仔细考虑。有时我们会想当然地把点击过的数据作为正样本,把没有点击的数据作为负样本。但是其实这样的做法是有潜在问题的。
例如有些用户其实就是在乱逛,那么他的点击其实不能提供很多的信息。而很多没有被点击的情况,可能是商品没有曝光、用户没有看到等原因导致的。所以要想比较准确地定位到合适的正负样本还是需要针对自己的数据场景仔细考虑。
● 6.4 过于依赖算法
这个问题相信很多同行也遇到过。我就举一个例子吧。我们当时遇到一个文本处理的问题,要过滤掉大量无关无用的文本词汇。一开始上了很多各种算法,各种调优,但是迟迟得不到满意的效果。
最后我们使用人工的方法解决了该问题。具体说就是三个人花了三天时间纯人工把文本过了一遍(几千个上万个词),效果立竿见影。当时的问题,或许是存在效果更好的算法的,但是从系统、工程角度整体衡量一下,还是人工的ROI最高。
所以虽然机器学习系统是以算法为主的系统,但是也不能思维僵化,凡事都只想着用算法解决,有的地方,还是“小米加步枪”比较合适。
● 6.5 关键流程和数据没有掌握在自己团队
这个问题可以说不是一个容易发现的问题,尤其是在系统初期,是比较隐蔽的。我们也是在吃了一些亏之后才发现这个问题的。
在很多公司里,前端展示,日志收集等工作是由专门的团队负责的,而诸如推荐广告这样的团队是直接拿来用的。这样做的好处很明显,可以让机器学习团队专注于本职工作,但是不好的一面是他们收集到的数据并不总是我们期望得到的。
举个例子。我们一开始使用的曝光数据是公司内其他团队帮我们做的,但是我们拿来之后发现和其他数据不太对得上,找了很久才找到问题。这个问题直接影响到我们拿到的样本的正确与否,所以对我们的影响非常的大。
那造成这个问题的原因是什么呢?其实并不是负责的团队不认真,而是他们并不完全理解我们对数据的需求,他们也不使用该数据,所以数据的质量就会有风险。吃了这个亏之后,我们现在把这部分工作也拿来自己做,这样数据正确与否我们可以全程监控,出了问题也可以自己内部解决,不用协调各种资源。
● 6.6 团队不够“全栈”
这是一个比较复杂的问题。在上一个问题中,我提到我们发现了数据质量有问题,之后自己做了这部分曝光收集的工作。但是定位问题原因和自己接手并不是在数据一有问题的时候就做到的。原因既简单又残酷:我们组里当时没有前端人才。
因为曝光问题涉及到从浏览器到后台系统的一系列动作,而前端是这些动作的第一个环节。但是我们在组建机器学习团队的时候,并没有意识到这里面会有前端什么事,以为有后台+模型的人就够了。所以导致我们面对这个问题比较无力。直到后来有一位有着丰富前端经验的同事加入我们组,我们才定位到问题,并且做出了自己接手的决定。
这个问题给我们的教训是组建团队的时候要更谨慎一些,要从更系统的角度看待,不能说做机器学习就只招算法工程师,这样会导致团队级的短板,为一些问题埋下伏笔。
● 6.7 巨型系统
最后一个问题,也是非常重要的一个问题,我称之为“巨型系统”。
巨型系统是什么意思呢?简单来说,就是把整个系统做成“一个”系统,而不是分模块做成多个子系统。做成一个系统的含义就是系统内部的模块之间有着高耦合性,强关联性,样本、特征、训练、预测等全部黏在一起,无法分离。这样做的后果是什么?
举例子。我们第一版的系统,光上线就上了有一周。而且之后的维护相当困难,想改东西非常困难。为什么会做成这样?
我的反思是:在学习机器学习理论的时候,就想当然得把样本、特征、训练这个pipeline当做一套东西了,这种思维直接反应到系统里就是一个巨型系统。或许在你只有十几个特征,几百条样本的时候没有问题。但是当你特征涨到几百万,样本涨到几千万的时候,就需要好好想一下,你的系统是不是有点大得失控了。
那更好的做法是什么呢?我们后来的解决方法是:大系统小做。 “大系统小做”这个说法不是我发明的,是微信团队在说抢红包系统架构时说到的一个概念,我觉得这个说法提炼得很。这个做法的意思就是,虽然你的系统很庞大,很复杂,但是做的时候还是要做好模块分离,这样利于开发,也利于扩展、维护。
机器学习系统的特点在于,刚开始你可能用的特征什么的都很少,所以觉得一个系统里就可以搞定,但是做着做着,需要对特征做各种变换,样本做各种处理,系统会在不知不觉中变得庞大,而如果你只关注模型的话,很容易造出一个无法维护的巨型系统来。
七、资料参考
我们的团队在经历了刚刚这许多“坑”之后,一个系统可以说是搭建起来了,但是这只是万里长征的第一步。对于我们如此,其实对于机器学习系统这个新事物,本身也有着不同于传统软件系统的诸多复杂之处,还有很多的挑战需要去解决。
我在这里用两篇参考文献简单介绍一下这些复杂之处,以及面对的挑战。有兴趣深入了解的同学可以找文章具体看看。
第一篇是Google Research的paper,讲的是机器学习技术债。题目也很有意思,可以翻译为:“机器学习:高利息的技术债信用卡”,如图7所示。这篇文章主要说的是机器学习系统的搭建非常的复杂,如果缺乏经验,或者不够谨慎,在许多环节就容易“欠债”,这些债务当时觉得影响不大,但是由于“利息”很高,到后来会让你还起来很痛苦。
图7 技术债的具体维度
图7所示是我看了文章之后,根据文章自己整理的技术债的几个具体维度。这几个维度和我们自己的实践也是高度吻合的。例如图中左上角提到的“子系统边界模糊”,和我之前说过的“巨型系统”有类似之处,说的也是系统内部无分割。
再例如右下角提到的“System-Level Spaghtti(系统级意大利面)”。意大利面代码常用来指代乱成一团的代码,由于机器学习系统一般都是在探索中搭建起来的,不像其他系统那样完全设计好再搭建,所以很容易产生意大利面代码。
如果能在搭建系统之前参照这些维度加以考虑,那么系统的开发、升级和维护会轻松很多。相信这些经验也是Google这样的巨头公司摔了很多坑总结出来的。巨头尚且如此,对我们来说自然也不简单。
第二篇文章是在FB的SGD大牛Leon Bottou中,在ICML 2015上做的一个tutorial。题目叫:Two big challenges in machine learning,如图8所示,是一篇比较偏系统实践的文章,说的是机器学习面临的两个新的挑战。
图8 Two big challenges in machine learning
第一点就非常地骇人听闻:机器学习破坏了软件工程。但是仔细想来,确实如此。机器学习系统的开发流程大多是探索式、渐进式的,这一点和传统的软件工程非常不同,这就给系统开发者们提出了挑战。我觉得以后很可能会出现专门的“机器学习系统架构师”职位。
第二点说的是当前的实验方式方法也遇到了极限。这一点乍一看是说科学实验的,其实不然。机器学习系统开发由于是探索式的,所以在开发中要经常做各种实验,验证各种效果,这个整体方法框架,也是需要精心设计的。显然在Bottou看来,目前的方法都不太合适。
八、 案例启示
本案例介绍了当当推荐团队的机器学习系统实践,其中着重介绍了系统构建的流程、方法、工具等,以教训为切入点介绍了机器学习系统构建的一些关键点,同时讨论了小团队在构建系统时的一些问题。
我们经验教训总起来主要为以下7点:
重视学习模型的同时,也非常重视整体系统。
正确认识并充分利用可视化分析工具。
算法优势与人工经验知识相结合。
重视系统结构,周期性重构。
重视团队完整性建设,确保团队无短板。
重视工具和数据的抽象和重用。
重视流程,重视项目推进方法。
最后我们对机器学习作为软件系统面临的挑战进行了讨论和展望。
★★征稿★★
寻找100个年度最具价值的实践案例
我们只要案例干货,拒绝广告
成为特约作者,你将:
◆ 连接100名年度经验与增长值TOP100的研发精英
◆ 提前入围「壹佰案例」年度最优案例榜单
◆ 案例整理成册,出版发行图书
◆ 成为msup客座教练
◆ 以观察员身份受邀出席壹佰案例
◆ 所在公司享有msup活动优惠
有意者guanzhu「壹佰案例」