机器学习最佳实践,Google机器学习43条军规:

本文是对Rules of Machine Learning: Best Practices for ML Engineering一文的翻译和解读。看过我翻译文章的同学知道我翻译文章一般都不太老实,没有那么“忠于原著”,本篇也不例外,本篇对于原文的解读大概有三种形式:

  • 原文翻译。对于作者本身阐述的比较好,而我也没什么可补充的部分,基本会原文翻译。
  • 半翻译半解读。有的条目我觉得有些自己的经验和感想可以和大家分享,就会加一些自己的解读在里面。
  • 省略。还有一些时候我觉得作者说的太仔(luo)细(suo),或者这个条目说得比较基本,无需太多解释,我就会不同程度的省略原文。

这种形式对于有的同学来讲可能会对原文信息有所损失,所以想要读到原文的同学,可以在这里找到原文:http://martin.zinkevich.org/rules_of_ml/rules_of_ml.pdf。 或者去搜一些其他人比较忠于原著的翻译。

作者介绍

什么样的NB人物写东西敢起号称”Rules of Machine Learning”这种不怕闪了腰的题目?首先我们来简单介绍一下本文的作者Martin Zinkevich。

Martin Zinkevich现在是谷歌大脑的高级科学家,负责和参与了YouTube、Google Play 以及Google Plus等产品中的机器学习项目,本文也是基于作者在这三个产品上面做机器学习项目的各种经验和教训提炼而成。在加入谷歌之前是雅虎的高级科学家,曾在2010年和2011年两度获得雅虎的最高荣誉Yahoo Team Superstar Awards,对雅虎的广告系统做出过很多杰出贡献。

拥有如此NB的背景,我们有理由相信这哥们儿写出来的东西还是具有足够的参考价值的。

梗概介绍

本文把在产品中应用机器学习的过程从浅到深分成了三个大的阶段,又在这三个大的阶段中细分出了一些方面,以此对43条规则进行逻辑分类。简单来说,如果你是从头开始做机器学习系统,那么就可以在不同阶段参考这里面对应的条目,来保证自己走在正确的道路上。

正文开始

To make great products:
do machine learning like the great engineer you are, not like the great machine learning expert you aren’t.

这句话一定程度上是对整篇文章(叫手册可能更合适)的一个高度概括,ML在实际工作确实更多是工程问题,而不是算法问题。优先从工程效率中要效果,当把这部分榨干后,再考虑算法的升级。

Before Machine Learning

Rule #1: Don’t be afraid to launch a product without machine learning.

规则1:不要害怕上线没有机器学习的产品。

中心思想一句话概括:If you think that machine learning will give you a 100% boost, then a heuristic will get you 50% of the way there.

Rule #2: First, design and implement metrics.

规则2:在动手之前先设计和实现评价指标。

在构建具体的机器学习系统之前,首先在当前系统中记录尽量详细的历史信息,留好特征数据。这样不仅能够留好特征数据,还能够帮助我们随时了解系统的状态,以及做各种改动时系统的变化。

Rule #3: Choose machine learning over a complex heuristic.

规则3:不要使用过于复杂的规则系统,使用机器学习系统。

简单来讲,复杂的规则系统难以维护,不可扩展,而我们很简单就可以转为ML系统,变得可维护可扩展。

ML Phase I: Your First Pipeline

构建第一个ML系统时,一定要更多关注系统架构的建设。虽然机器学习的算法令人激动,但是基础架构不给力找不到问题时会令人抓狂。

Rule #4: Keep the first model simple and get the infrastructure right.

规则4:第一个模型要简单,但是架构要正确。

第一版模型的核心思想是抓住主要特征、与应用尽量贴合以及快速上线。

Rule #5: Test the infrastructure independently from the machine learning.

规则5:独立于机器学习来测试架构流程。

确保架构是可单独测试的,将系统的训练部分进行封装,以确保其他部分都是可测试的。特别来讲:

  1. 测试数据是否正确进入训练算法。检查具体的特征值是否符合预期。
  2. 测试实验环境给出的预测结果与线上预测结果是否一致。

Rule #6: Be careful about dropped data when copying pipelines.

规则6:复制pipeline时要注意丢弃的数据。

从一个场景复制数据到另一个场景时,要注意两边对数据的要求是否一致,是否有数据丢失的情况。

Rule #7: Turn heuristics into features, or handle them externally.

规则7:将启发规则转化为特征,或者在外部处理它们。

机器学习系统解决的问题通常都不是新问题,而是对已有问题的进一步优化。这意味着有很多已有的规则或者启发式规则可供使用。这部分信息应该被充分利用(例如基于规则的推荐排序时用到的排序规则)。下面是几种启发式规则可以被使用的方式:

  1. 用启发规则进行预处理。如果启发式规则非常有用,可以这么用。例如在垃圾邮件识别中,如果有发件人已经被拉黑了,那么就不要再去学“拉黑”意味着什么,直接拉黑就好了。
  2. 制造特征。可以考虑从启发式规则直接制造一个特征。例如,你使用启发式规则来计算query的相关性,那么就可以把这个相关性得分作为特征使用。后面也可以考虑将计算相关性得分的原始数据作为特征,以期获得更多的信息。
  3. 挖掘启发式规则的原始输入。如果有一个app的规则启发式规则综合了下载数、标题文字长度等信息,可以考虑将这些原始信息单独作为特征使用。
  4. 修改label。当你觉得启发式规则中包含了样本中没有包含的信息时可以这么用。例如,如果你想最大化下载数,同时还想要追求下载内容的质量。一种可行的方法是将label乘以app的平均star数。在电商领域,也常常用类似的方法,例如在点击率预估的项目中,可考虑对最终下单的商品或者高质量的商品对应的样本增加权重。

已有的启发式规则可以帮助机器学习系统更平滑的过渡,但是也要考虑是否有同等效果更简单的实现方式。

Monitoring

概括来讲,要保持好的监控习惯,例如使报警是可应对的,以及建设一个Dashboard页面。

Rule #8: Know the freshness requirements of your system.

规则8:了解你系统对新鲜度的要求。

如果模型延迟一天更新,你的系统会受到多大的效果影响?如果是一周的延迟呢?或者更久?这个信息可以让我们排布监控的优先级。如果模型一天不更新收入就会下降10%,那么可以考虑让一个工程师全天候监控它。了解系统对新鲜度的要求是决定具体监控方案的第一步。

Rule #9: Detect problems before exporting models.

规则9:在模型上线之前检测问题。

模型上线前一定要做完整性、正确性检查,例如AUC、Calibration、NE等指标的计算确认等。如果是模型上线前出了问题,可以邮件通知,如果是用户正在使用的模型出了问题,就需要电话通知了。

Rule #10: Watch for silent failures.

规则10:关注静默失败。

这是一个非常重要,而又经常容易被忽略的问题。所谓的静默失败指的是全部流程都正常完成,但是背后依赖数据出了问题,导致模型效果逐步下降的问题。这种问题在其他系统中并不常出现,但是在机器学习系统中出现几率会比较高。例如训练依赖的某张数据表很久没有更新了,或者表中的数据含义发生了变化等,再或者数据的覆盖度忽然变少,都会对效果产生很大的影响。解决方法是是对关键数据的统计信息进行监控,并且周期性对关键数据进行人工检查。

Rule #11: Give feature column owners and documentation.

规则11:给特征组分配负责人,并记录文档。

这里的feature column指的是一个特征组,例如用户可能属于的国家这组特征就是一个feature column。

如果系统庞大,数据繁多,那么知道每组数据由谁生成就变得非常重要。虽然数据都有简单描述,但是关于特征的具体计算逻辑,数据来源等都需要更详细的记录。

Your Fist Objective

objective是模型试图优化的值,而metric指的是任何用来衡量系统的值。

Rule #12: Don’t overthink which objective you choose to directly optimize.

规则12:不要过于纠结该优化哪个目标。

机器学习上线的初期,即使你只优化一个目标,很多指标一般都会一起上涨的。所以不用太纠结究竟该优化哪个。

虽然大佬这么说,但是在我自己的实践经验中,只优化一个目标,系统的整体效果却未必会上涨。典型的如推荐系统的CTR模型,上线之后CTR确实会提升,但是对应的CVR很有可能会下降,这时还需要一个CVR模型,两个模型同时使用才能真正提升系统效果。究其原因,是因为每个目标只关注系统整个过程的一个子过程,贪心地去优化这个子过程,不一定能够得到全局的最优解,通常需要把主要的几个子过程都优化之后,才能取得整体效果的提升。

Rule #13: Choose a simple, observable and attributable metric for your first objective.

规则13:为你的第一个objective选择一个简单可观测可归因的metric。

objective应该是简单可衡量的,并且是metric的有效代理。最适合被建模的是可直接观测并被归因的行为,例如:

  1. 链接是否被点击?
  2. 软件是否被下载?
  3. 邮件是否被转发?
    ……

尽量不要在第一次就建模非直接效果的行为,例如:

  1. 用户第二天是否会访问?
  2. 用户在网站上停留了多久?
  3. 日活用户有多少?

非直接指标是很好的metric,可以用ABTest来进行观测,但不适合用作优化指标。此外,千万不要试图学习以下目标:

  1. 用户对产品是否满意?
  2. 用户对体验是否满意?
    ……

这些指标非常重要,但是非常难以学习。应该使用一些代理指标来学习,通过优化代理指标来优化这些非直接指标。为了公司的发展着想,最好有人工来连接机器学习的学习目标和产品业务。

Rule #14: Starting with an interpretable model makes debugging easier.

规则14:使用可解释性强的模型可降低debug难度。

优先选择预测结果有概率含义、预测过程可解释的模型,可以更容易的确认效果,debug问题。例如,如果使用LR做分类,那么预测过程不外乎一些相乘和相加,如果特征都做了离散化,就只有加法了,这样很容易debug一条样本的预测得分是如何被计算出来的。所以出了问题很容易debug。

Rule #15: Separate Spam Filtering and Quality Ranking in a Policy Layer.

规则15:将垃圾过滤和质量排序的工作分离,放到策略层(policy layer)。

排序系统工作的环境中数据分布是相对静态的,大家为了得到更好的排序,会遵守系统制定的规则。但是垃圾过滤更多是个对抗性质的工作,数据分布会经常变动。所以不应该让排序系统去处理垃圾信息的过滤,而是应该有单独的一层去处理垃圾信息。这也是一种可以推广的思想,那就是:排序层只做排序层的事情,职责尽量单一,其他工作让架构上更合适的模块去处理。此外,为了提升模型效果,应该把垃圾信息从训练数据中去除。

ML Phase II: Feature Engineering

前面第一阶段的重点是把数据喂到学习系统中,有了基础的监控指标,有了基础的架构。等这一套系统建立起来后,第二阶段就开始了。

整体来讲,第二阶段的核心工作是将尽量多的有效特征加入到第一版的系统中,一般都可以取得提升。

Rule #16: Plan to launch and iterate.

规则16:做好持续迭代上线的准备。

简单来说,就是要深刻认识到,系统优化永远没有终点,所以系统设计方面要对迭代非常友好。例如增加删除特征是否足够简单,正确性验证是否足够简单,模型迭代是否可以并行运行,等等。

这虽然不是一条具体可行动的(actionable)规则,但是这种思想上的准备对整个系统的开发很有帮助。只有真正深刻意识到了系统持续迭代上线的本质,才会在设计在线和离线架构时为持续迭代最好相应的设计,并做好相应的工具,而不是做一锤子系统。

Rule #17: Start with directly observed and reported features as opposed to learned features.

规则17:优先使用直接观测或收集到的特征,而不是学习出来的特征。

所谓学习出来的特征,指的是用另外的算法学习出来的特征,而非可以直接观测或收集到的简单特征。学习出来的特征由于存在外部依赖,或者计算逻辑复杂,不一定适用于你当前的模型,所以稳定性和有效性会有风险。而直接可观测的特征由于是相对比较客观的,依赖较少的,所以比较稳定。

Rule #18: Explore with features of content that generalize across contexts.

规则18:探索使用可以跨场景的内容特征。

中心思想是在说,要多利用可以在多个场景下使用的特征,例如全局的点击率、浏览量这些特征,可以在多个场景下作为特征使用。这样可以在一些冷启动或者缺乏有效特征的场景下作为特征使用。

Rule #19: Use very specific features when you can.

规则19:尽量使用非常具体的特征。

如果数据量足够大,那么相比少数复杂特征,使用海量简单特征是更简单有效的选择。

所谓非常具体,指的是覆盖样本量比较少的特征,例如文档的ID或者query的ID等。这样的特征虽然每个只覆盖很少一部分特征,但是只要这一组特征整体能够覆盖率比较高,例如90%,那就是OK的。而且还可以通过正则化来消除覆盖率过低或者相关性差的特征。这也是大家都偏爱大规模ID特征的一个原因,现在很多大厂的排序模型特征都大量使用了大规模ID特征。

Rule #20: Combine and modify existing features to create new features in human­-understandable ways.

规则20:用人类可理解的方式对已有特征进行组合、修改来得到新特征。

离散化和交叉是最常用的两种特征使用方式。其本质都是用特征工程的方式,在不改变使用模型本身的情况下增加模型的非线性。这两种方法本身没什么好说的,值得一致的是,在大规模ID类特征的交叉时,例如一段是query里的关键词,另一端是文档里的关键词,那就会产生很大量级的交叉特征,这时有两种处理方法:

  1. 点积。其实计算query和文档共同包含的关键词数量。
  2. 交集。每一维特征的含义是某个词同时出现在了query和文档中,同时出现则该维特征为1,否则为0。

所谓“人类可理解的方式”,我的理解就是离散化和交叉要基于对业务逻辑的理解,不能乱交叉。

Rule #21: The number of feature weights you can learn in a linear model is roughly proportional to the amount of data you have.

规则21:线性模型中可学到的特征权重数量,与训练数据的数量大体成正比。

这背后有复杂的统计原理做支撑,但你只需要知道结论就可以了。这个原则给我们的启示,是要根据数据量来选择特征的生成方式,例如:

  1. 如果你的系统是一个搜索系统,query和文档中有百万级的词,但是你只有千级别的标注样本。那你就别用ID级关键词特征了,而是要考虑点积类特征,把特征数量控制在几十个这个级别。
  2. 如果你拥有百万级样本,那么可以将文档和query的关键词进行交叉特征,然后用正则化进行特征选择。这样你会得到百万级特征,但是正则化之后会更少。所以说,千万级样本,十万级特征。
  3. 如果你有十亿级或者更高级别的样本,那么你可以使用query和文档的ID级特征,然后加上特征选择和正则化。十亿级样本,千万级特征。

总结起来就是,根据样本决定特征使用方式,样本不够就对特征进行高层次抽象处理,指导和样本量级相匹配。

Rule #22: Clean up features you are no longer using.

规则22:清理不再使用的特征。

如果某个特征已经没有用,并且它与其他特征的交叉也已经没有用,就应该将其清理掉,保持架构的整洁性。

在考虑添加或保留哪些特征时,需要统计一下特征的样本覆盖率,例如一些整体覆盖率很低的个性化feature column,只有很少用户能覆盖到,那么大概率这组特征作用不大。但另一方面,如果某个特征覆盖率很低,例如只有1%,但是其区分度非常大,例如90%取值为1的样本都是正样本,那么 这个特征就值得加入或保留。

Human Analysis of the System

在更进一步之前,我们需要了解一些机器学习课程上不会教你的内容:如何观察分析模型,并改进它。用作者的话说,这更像是一门艺术 ,但仍然有一些规律可循。

Rule #23: You are not a typical end user.

规则23:你不是一个典型的终端用户。

这条规则的中心思想是说,虽然吃自己的狗食是必要的,但也不要总是从工程师的角度来衡量模型的好坏。这不仅可能不值当,而且可能看不出问题。所谓不值当,是因为工程师的时间太贵了,这个大家都懂;而所谓看不出问题,是因为工程师自己看自己开发的模型,容易看不出问题,所谓“不识庐山真面目”。

所以作者认为合理的方法是让真正的终端用户来衡量模型或产品的好坏。要么通过线上ABTest,要么通过众包的方式来做。

Rule #24: Measure the delta between models.

规则24:离线衡量模型之间的差异。

原文没有说是离线,但我通过上下文理解他说的应该是离线。这一条规则说的是新模型在上线之前,需要先和老模型做差异对比。所谓差异对比,指的是对于同样的输入,新旧两个模型给出的结果是否差异足够大。例如对于同一个query,两个排序模型给出的差异是否足够大。如果离线计算发现差异很小,那也没必要上线测试了,因为上线后差异肯定也大不了。如果差异比较大,那么还需要看差异是不是好的差异。通过观察差异可以得知新模型究竟对数据产生了什么影响,这种影响是好是坏。

当然,这一切的前提是你需要有一个稳定的对比系统, 起码一个模型和他自己对比的话差异应该非常小,最好是零差异。

Rule #25: When choosing models, utilitarian performance trumps predictive power.

规则25:当选择模型时,实用性指标比预测能力更重要。

这是一条很有用的经验。虽然我们训练模型时objective一般都是logloss,也就是说实在追求模型的预测能力。但是我们在上层应用中却可能有多种用途,例如可能会用来排序,那么这时具体的预测能力就不如排序能力重要;如果用来划定阈值然后跟根据阈值判断垃圾邮件,那么准确率就更重要。当然大多数情况下这几个指标是一致的。

除了作者说的这一点,还有一种情况是需要特别注意的,那就是我们在训练时可能会对样本做采样,导致得到的预测值整体偏高或偏低。如果这个预测值是用来直接排序的,那么这个变化关系不大,但如果有其他用处,例如和另外的值相乘,典型的如广告场景下的CTR*bid,或者电商推荐排序下的CTR*CVR,在这类场景下,预测值本身的准确性也很重要,就需要对其进行校准(calibrate),使其与采样前的样本点击率对齐。

Rule #26: Look for patterns in the measured errors, and create new features.

规则26:在错误中发现模式,并创建新特征。

这算是一种用来提升模型效果的通用思路。具体来说,指的是观察训练数据中模型预测错误的样本,看看是否能够通过添加额外特征来使得这条样本被模型预测正确。之所以使用训练集中的数据,是因为这部分数据是模型已经试图优化过的,这里面的错误,是模型知道自己搞错了,目前学不出来的,所以如果你给它足够好的其他特征,它或许就能把这条样本学对了。

一旦发现错误的模式,就可以在当前系统之外寻找新的特征。例如,如果你发现当前系统倾向于错误地把长文章排到后面,那么就可以加入文章长度这一特征,让系统去学习文章长度的相关性和重要性。

Rule #27: Try to quantify observed undesirable behavior.

规则27:尽量将观测到的负面行为量化。

如果在系统中观察到了模型没有优化到的问题,典型的例如推荐系统逼格不够这种问题,这时应该努力将这种不满意转化为具体的数字,具体来讲可以通过人工标注等方法标注出不满意的物品,然后进行统计。如果问题可以被量化,后面就可以将其用作特征、objective或者metric。整体原则就是“先量化,再优化”。

多说一句,这里的优化,不一定是用模型来优化,而是指的整体优化。比如推荐系统逼格这种问题,模型可能很难优化,但是只要能量化出来,就可以通过其他方法来尽量减少,例如单独去学习有逼格物品的特征,或者在召回阶段进行一定倾斜。

Rule #28: Be aware that identical short-­term behavior does not imply identical long­-term behavior.

规则28:要注意短期内观察到的类似行为不一定会长期存在。

假设你搞了个系统,通过学习每个具体的文档ID和query ID,计算出了每个query下每个文档的点击率。通过离线对比和ABTest,你发现这个系统的行为和当前系统的行为一毛一样,而这个系统又更简单,所以你就把这个系统上线了。后面你会发现这个系统在任何query下都不会给出任何新的文档。奇怪吗?一点都不奇怪,因为你只让它记住了之前的历史数据,它对新数据没有任何信息。

所以唯一能够衡量一个系统是否长期有效的方法,就是让它使用该模型在线上时收集到的真实数据上进行训练。当然这有难度。

往大了说,作者这条规则其实说的是个系统或者模型的泛化能力,如果一个系统或者模型不能对新数据做出很好的预测,那么无论他的离线表现如何,都不能代表它的真正能力。再换个角度来看,一个系统必须具有持续学习适应新数据的能力,才能是一个合格的机器学习系统,否则就只是个学舌的鹦鹉。

Training-Serving Skew

训练和服务之间的差异问题时一个大话题,主要原因包括训练时与服务时数据获取方式不同、训练时与服务时数据分布不同以及模型和算法之间的反馈循环等。作者说这种差异在G家的多条产品线上出现过,都产生了负面影响。但要我说这绝对不仅仅是谷歌的问题,谷歌绝对是做的比较好的了,各种中小厂里面这种问题只多不少,所以这部分的经验是非常宝贵的。解决这类问题的核心是对系统和数据的变化进行监控,确保一切差异都在监控之内,不会悄悄进入系统。

Rule #29: The best way to make sure that you train like you serve is to save the set of features used at serving time, and then pipe those features to a log to use them at training time.

规则29:保证服务与训练一致性的最好方法是将服务时的特征保存下来,然后通过日志将特征喂到训练过程中去。

这句话基本道出了保证差异最小化的核心套路。这种基于特征日志的方法可以极大提升效果,同时能够减少代码复杂度。谷歌的很多团队也正在往这种做法上迁移。

Rule #30: Importance weight sampled data, don’t arbitrarily drop it!

规则30:对采样样本做重要性赋权,不要随意丢弃!

这是作者唯一用了感叹号的一条,可想而知背后的辛酸。当我们有太多训练数据时,我们会只取其中的一部分。但这是错误的。正确的做法是,如果你给某条样本30%的采样权重,那么在训练时就给它10/3的训练权重。通过这样的重要性赋权(importance weight),整个训练结果的校准性(calibration)就还能够保证。

多说一句,这个校准性非常的重要,尤其对于广告系统,或者多个预测值相加或相乘来得到最终结果的系统。如果单个值没有校准,偏低或偏高,那么在相乘或相加之后其含义就会不正确。如果直接使用模型预测值进行排序,校准性就没那么重要,因为校准性不会影响排序,只会影响具体的值。

Rule #31: Beware that if you join data from a table at training and serving time, the data in the table may change.

规则31:如果你在训练时和服务时都在join一张表,那么要注意这张表的数据可能会发生变化。

比如说某张表里存着一些文档的特征,你在离线训练之前要去这个表里取这些特征用来训练,但这里就有个风险,那就是这个表里的数据在你离线取的时候和在线服务的时候数据不一样,发生了变化。最好的解决方式就是在服务端将特征记录在日志中,这样能保证数据的一致性。或者如果这张表的变化频率比较低,也可以考虑对其做小时级或天级备份,以此来减少这种差异。但要记住这种方法并不能彻底解决这个问题。

Rule #32: Re­use code between your training pipeline and your serving pipeline whenever possible.

规则32:尽量在训练pipeline和服务pipeline之间复用代码。

训练一般是离线批量进行的,而服务则是在线流式进行的,这两者之间虽然在处理数据的方式上存在着较大差异,但仍然有很多代码可以共享。这些代码的共享可以从代码层面介绍训练和服务之间的差异。换句话说,日志记录特征是从数据角度消除差异,那么代码复用就是从代码角度消除差异,双管齐下,效果更好。

Rule #33: If you produce a model based on the data until January 5th, test the model on the data from January 6th and after.

规则33:如果训练数据是1月5日之前的,那么测试数据要从1月6日开始。

这条规则的主要目的是让测试结果与线上结果更加接近,因为我们在使用模型时就是在用服务当天之前的数据训练,然后来预测当天的数据。这样得到的测试结果虽然可能会偏低,但却更加真实。

Rule #34: In binary classification for filtering (such as spam detection or determining interesting e­mails), make small short-­term sacrifices in performance for very clean data.

规则34:在为过滤服务的二分类问题中(例如垃圾邮件过滤),可以为了干净的数据牺牲一些短期效果。

在过滤类的任务中,被标记为负的样本是不会展示给用户的,例如可能会把75%标记为负的样本阻拦住不展现给用户。但如果你只从展示给用户的结果中获取下次训练的样本,显然你的训练样本是有偏的。

更好的做法是使用一定比例的流量(例如1%)专门收集训练数据,在这部分流量中的用户会看到所有的样本。这样显然会影响线上的真实过滤效果,但是会收集到更好的数据,更有利于系统的长远发展。否则系统会越训练越偏,慢慢就不可用了。同时还能保证至少过滤掉74%的负样本,对系统的影响也不是很大。

但是如果你的系统会过滤掉95%或者更多的负样本,这种做法就不那么可行了。即使如此,为了准确衡量模型的效果,你仍然可以通过构造一个更小的数据集(0.1%或者更小)来测试。十万级别的样本足够给出准确的评价指标了。

Rule #35: Beware of the inherent skew in ranking problems.

规则35:注意排序问题中固有的数据偏置。

当新的排序算法对线上排序结果产生了重大改变时,你其实是改变了算法将来会看到的数据。这时这种偏置就会出现。这种问题有以下几种方法来解决,核心思想都是更偏重模型已经看到过的数据。

  1. 对覆盖更多query(或类似角色,根据业务不同)的特征给予更强的正则化。这样模型会更偏重只覆盖一部分样本的特征,而不是泛化性特征。这样会阻止爆品出现在不相关query的结果中。
  2. 只允许特征取正的权重值。这样任何好特征都会比“未知”特征要好。
  3. 不要使用只和文档相关的特征。这是第一条的极端情况,否则会导致类似哈利波特效应的情况出现,也就是一条在任何query下都受欢迎的文档不会到处都出现。去除掉只和文档相关的特征会阻止这种情况发生。

Rule #36: Avoid feedback loops with positional features.

规则36:使用位置特征来避免反馈回路。

大家都知道排序位置本身就会影响用户是否会对物品产生互动,例如点击。所以如果模型中没有位置特征,本来由于位置导致的影响会被算到其他特征头上去,导致模型不够准。可以用加入位置特征的方法来避免这种问题,具体来讲,在训练时加入位置特征,预测时去掉位置特征,或者给所有样本一样的位置特征。这样会让模型更正确地分配特征的权重。

需要注意的是,位置特征要保持相对独立,不要与其他特征发生关联。可以将位置相关的特征用一个函数表达,然后将其他特征用另外的函数表达,然后组合起来。具体应用中,可以通过位置特征不与任何其他特征交叉来实现这个目的。

Rule #37: Measure Training/Serving Skew.

规则37:衡量训练和服务之间的差异。

整体来讲有多种原因会导致这种差异,我们可以将其进行细分为以下几部分:

  1. 训练集和测试集之间的差异。这种差异会经常存在,而且不一定是坏事。
  2. 测试集和“第二天”数据间的差异。这种差异也会一直存在,而这个“第二天”数据上的表现是我们应该努力优化的,例如通过正则化。这两者之间差异如果过大,可能是因为用到了一些时间敏感的特征,导致模型效果变化明显。
  3. “第二天”数据和线上数据间的差异。如果同样一条样本,在训练时给出的结果和线上服务时给出的结果不一致,那么这意味着工程实现中出现了bug。

ML Phase III: Slowed Growth, Optimization Refinement, and Complex Models

一般会有一些明确的信号来标识第二阶段的尾声。首先,每月的提升会逐步降低。你开始在不同指标之间做权衡,有的上升有的下降。嗯,游戏变得有趣了。既然收益不容易获得了,机器学习就得变得更复杂了。

在前两个阶段,大部分团队都可以过得很开心,但到了这个阶段,每个团队都需要找到适合自己的路。

Rule #38: Don’t waste time on new features if unaligned objectives have become the issue.

规则38:如果objective没有达成一致,不要在新特征上浪费时间。

当系统整体达到一个稳定期,大家会开始关注机器学习系统优化目标以外的一些问题。这个时候,目标就不如之前那么清晰,那么如果目标没有确定下来的话,先不要在特征上浪费时间。

Rule #39: Launch decisions are a proxy for long­term product goals.

规则39:上线决策是长期产品目标的代理。

这句话读起来有点别扭,作者举了几个例子来说明,我觉得核心就是在讲一件事情:系统、产品甚至公司的长远发展需要通过多个指标来综合衡量,而新模型是否上线要综合考虑这些指标。所谓代理,指的就是优化这些综合指标就是在优化产品、公司的长远目标。

决策只有在所有指标都在变好的情况下才会变得简单。但常常事情没那么简单,尤其是当不同指标之间无法换算的时候,例如A系统有一百万日活和四百万日收入,B系统有两百万日活和两百万日收入,你会从A切换到B吗?或者反过来?答案是或许都不会,因为你不知道某个指标的提升是否会cover另外一个指标的下降。

关键是,没有任何一个指标能回答:“五年后我的产品在哪里”?

而每个个体,尤其是工程师们,显然更喜欢能够直接优化的目标,而这也是机器学习系统常见的场景 。现在也有一些多目标学习系统在试图解决这种问题。但仍然有很多目标无法建模为机器学习问题,比如用户为什么会来访问你的网站等等。作者说这是个AI-complete问题,也常被称为强AI问题,简单来说就是不能用某个单一算法解决的问题。

Rule #40: Keep ensembles simple.

规则40:ensemble策略保持简单。

什么叫简单的ensemble?作者认为,只接受其他模型的输出作为输入,不附带其他特征的ensemble,叫做简单的ensemble。换句话说,你的模型要么是单纯的ensemble模型,要么是普通的接收大量特征的基模型。

除了保持简单,ensemble模型最好还能具有一些良好的性质。例如,某个基模型的性能提升不能降低组合模型的性能。以及,基模型最好都是可解释的(例如是校准的),这样基模型的变化对上层的组合模型来说也是可解释的。同时,一个基模型预测概率值的提升不会降低组合模型的预测概率值。

Rule #41: When performance plateaus, look for qualitatively new sources of information to add rather than refining existing signals.

规则41:当效果进入稳定期,寻找本质上新的信息源,而不是优化已有的信号。

你加了一些用户的人口统计学特征,你加了一些文档的文字特征,等等,但是关键指标上的提升还不到1%。现在咋整?

这时就应该考虑加一些根本上不同的特征,例如用户再过去一天、一周看过的文档历史,或者另外一个数据源的数据。总之,要加入完全不同的维度的特征。此外也可以尝试使用深度学习,但同时也要调整你对ROI的预期,并且要评估增加的复杂度换来的收益是否值得。

Rule #42: Don’t expect diversity, personalization, or relevance to be as correlated with popularity as you think they are.

规则42:多样性,个性化或者相关性与流行度的相关性关系可能要比你想的弱很多。

多样性意味着内容或者来源的多样性;个性化意味着每个用户得到不一样的东西;相关性意味着一个query的返回结果相比其他query与这个query更相关。所以这三个指标的含义都是与普通不一样。

但问题在于普通的东西很难被打败。

如果你的衡量指标是点击、停留时长、观看数、分享数等等,你本质上是在衡量东西的流行度。有的团队有时会希望学到一个多样化的个性化模型。为此,会加入个性化特征和多样化特征,但是最后会发现这些特征并没有得到预期的权重。

这并不能说明多样性、个性化和相关性不重要。像前文指出,可以通过后续的处理来增加多样性或相关性。如果这时看到长期目标提升了,你就可以确定多样性/相关性是有用的。这时你就可以选择继续使用后续处理的方式,或者根据多样性和相关性直接修改要优化的objective。

Rule #43: Your friends tend to be the same across different products. Your interests tend not to be.

规则43:你在不同产品上的好友一般是一样的,但你的兴趣通常会不一样。

谷歌经常在不同产品上使用同样的好友关系预测模型,并且取得了很好的效果,这证明不同的产品上好友关系是可以迁移的,毕竟他们是固定的同一批人。但他们尝试将一个产品上的个性化特征使用到另外一个产品上时却常常得不到好结果。可行的做法是使用一个数据源上的原始数据来预测另外数据源上的行为,而不是使用加工后的特征。此外,用户在另一个数据源上的行为历史也会有用。

总结

从上面洋洋洒洒43条经验之谈中不难看出,大神作者认为,对于大多数机器学习应用场景来说,我们需要解决的问题大多数都是工程问题,解决这些工程问题需要的并不是复杂的理论,更多是对细节、架构、过程的仔细推敲和精致追求。而这些是我们非大神的普通人可以做到的,如果说大神做的是95分以上的系统,那么我们只要对工程架构、过程和细节做好足够的优化,我们也可以做出至少80分的系统。

译者简介:张相於([email protected]),现任转转推荐系统负责人,负责转转的推荐系统。曾任当当网推荐系统开发经理,多年来主要从事推荐系统以及机器学习相关工作,也做过反垃圾、反作弊相关工作,并热衷于探索大数据技术&机器学习技术在其他领域的应用实践。他正在招推荐算法和推荐架构工程师,有意请邮件发送简历联系。


----------------------------------------------------------------------------------------------------------------------------------

本文来源:《Rules of Machine Learning:Best Practices for ML Engineering》

作者:Martin Zinkevich google 研究科学家。

这是Martin Zinkevich在NIPS 2016 Workshop 分享的谷歌机器学习实践的四十三条法则。
术语

实体(Instance):要对其进行预测的事物

标签(Label):预测任务的结果

特征:在预测任务中用到的实体的一个属性

特征集(feature Column):相关特征的一个集合

样例(Example):实体(及它的特征)和标签的集合

模型(Model):关于一个预测任务的一个统计表示。在样例中训练一个模型,然后用这个模型来预测

指标(metric):你关心的一些东西。有可能直接优化。

目标(Objective):你的算法尝试去优化的一个指标

工作流(pipeline):关于一个机器学习算法所有的基础构件。包括从前端收集数据,将数据输入训练数据文件,训练一个或者更多模型,以及将模型导出用于生产。
概述

要想创造出优秀的产品:

你需要以一位优秀工程师的身份去运用机器学习,而不是作为一位伟大的机器学习专家(而事实上你并不是)。

事实上,你所面临的大多数问题都是技术性问题。即便拥有足以媲美机器学习专家的理论知识。要想有所突破,大多数情况下都在依赖示例良好特征而非优秀的机器学习算法。因此,基本方法如下:

1.确保你的 工作流 各连接端十分可靠

  1. 树立合理的目标

  2. 添加的常识性特征尽量简单

  3. 确保你的 工作流 始终可靠

这种方法能带来相当多的盈利,也能在较长时间里令许多人都满意,甚至还可能实现双赢。只有在简单技巧不发挥任何作用的情况下,才考虑使用复杂的一些的方法。方法越复杂,产品最终输出速度慢。

当所有的简单技巧用完后,很可能就要考虑最前沿机器学习术了。

本文档主要由四部分组成:

第一部分:帮助你明白是否到了需要构建一个机器学习系统

第二部分:部署你的第一个工作流

第三部分:往工作流增加新特征时的发布和迭代,以及如何评价模型和训练-服务倾斜(training-serving shew)

第四部分:达到稳定阶段后该继续做什么。

在机器学习之前

法则1:不用害怕发布一款没有用到机器学习的产品

机器学习很酷,但它需要数据。如果不是绝对需要机器学习,那在没有数据前,不要使用它。

法则2:将度量标准的设计和执行置于首位

在定义你的机器学习系统将要做什么前,尽可能的记录你当前的系统“足迹”。原因:

1、在早期,获得系统用户的许可相对容易.

2、如果你认为某些事在将来会重要,那么最好是从现在开始就收集历史数据

3、如果你设计系统时,就已经在心里有度量指标,那么将来一切就会更加的顺畅。特别是你肯定不想为了测量你的指标而需要在日志中执行grep。

4、你能够注意到什么改变了,什么没有变。比如,假如你想要直接优化每日活跃用户。但是,在你早期对系统的管理中,你可能注意到对用户体验的急剧改变,可能并不会明显的改变这个指标。

Google Plus团队测量“转发数”(expands per read)、分享数(reshares per read)、点赞数(plus-ones per read)、评论/阅读比(comments/read)、每个用户的评论数、每个用户的分享数等。这些用来在服务时间衡量一篇帖子的质量。同样,有一个能够将用户聚成组,并实验生成统计结果的实验框架很重要。见法则12

法则3:在机器学习和启发式方法中优先选择机器学习。

机器学习模型更好更新和更容易管理

机器学习阶段1:第一条工作流

认真对待第一条工作流的基础架构建设。虽然发挥想象力构思模型很有意思,但首先得确保你的工作流是可靠的,这样出了问题才容易发现。

法则4:第一个模型要简单,基础架构要正确。

第一个模型对你的产品提高最大,因此它不需要有多神奇。相反,你会碰到比你想象的多的基础架构方面的问题。在别人使用你的神奇的新机器学习系统前,你要决定:

1、如何为学习算法得到样本

2、对于你的系统,“好”、“坏”的定义是什么

3、如何在你的应用中融入你的模型。你可以在线应用你的模型,也可以在离线预先计算好模型,然后将结果保存到表中。比如,你可能想要预分类网页并将结果存入表,也有可能你想直接在线上分类聊天信息。

选择简单的特征,以能够更容易确保:

1、这些特征正确应用于学习算法

2、模型能够学习到合理的权重

3、这些特征正确应用于服务器模型。

你的系统如果能够可靠地遵守这三点,你就完成了大多数工作。你的简单模型能够提供基准指标和基准行为,你可以用来测量更加复杂的模型。

法则5:单独测试基础架构。

确保基础架构是可测试的。系统的学习部分独立封装,因此所有围绕它的都能测试。

法则6:复制工作流时留意丢失的数据

我们有时候会通过复制已经存在的工作流来创建一个新的工作流。在新的工作流中需要的数据,很可能在旧的数据流就丢弃了。比如,仅仅记录那些用户看到过的帖子的数据,那么,如果我们想要建模“为什么一篇特定的帖子没有被用户阅读”时,这些数据就没用了。

法则7:要么把启发式方法转化为特征,要么在外部处理它们

机器学习尝试解决的问题通常并不完全是新的。可以利用到很多已有的规则和启发式方法。当你调整机器学习时,这些相同的启发式方法能提供非常有用的帮助。
监控

一般来说,实施良好的警报监控,例如使警报可操作并具有报表页面。

法则8:了解系统的新鲜度要求

如果系统是一天前的,性能会降低多少?如果是一个星期前,或者1个季度前的呢? 知道这些能够帮助你理解监控的优先级。如果模型一天未更新,你的收入会下降10%,那最好是有个工程师持续不断的关注。大多数广告服务系统每天都有新广告要处理,因此必须每日更新。有些需要频繁更新,有些又不需要,这因不同的应用和场景而定。此外,新鲜度也会因时间而异,特别是你的模型会增加或移除特征时。

法则9:导出(发布)你的模型前,务必检查各种问题

将模型导出部署到线上服务。如果这个时候,你的模型出了问题,这就是一个用户看到的问题。但如果是在之前出现问题,那就是一个训练问题,用户并不会发现。

在导出模型前务必进行完整性的检查。特别是要确保对留存的数据,你的模型能够满足性能。如果对数据感觉有问题,就不用导出模型!很多持续部署模型的团队都会在导出前检测AUC。模型问题出现在导出前,会收到警告邮件,但如果模型问题让用户碰到,就可能需要一纸辞退信了。因此,在影响用户前,最好先等一等,有确定把握后,在导出。

法则10:注意隐藏性失败

相对其他类型的系统,机器学习系统出现这种问题的可能性更高。比如关联的某张表不再更新。虽然机器学习还是会照样调整,行为还是表现的很合适,但已经在逐渐衰落。有时候发现了那些已经数月没有更新的表,那这个时候,一个简单的更新要比其他任何改变都能更好的提高性能。比如,由于实现的改变,一个特征的覆盖率会变:比如,开始覆盖90%的样本,突然只能覆盖60%了。google Play做过一个实验,有张表6个月一直不变,仅仅是对这个表更新,就在安装率方面提高了2%。跟踪数据的统计,并且在必要的时候人工检查,你就可以减少这样的错误。

法则11:给特征指定作者和文档

如果系统很大,有很多的特征,务必要知道每个特征的创建者或者管理者。如果理解特征的人要离职,务必确保有其他人理解这个特征。尽管很多的特征的名字已基本描述了特征的意义,但对特征有更新详细的描述,比如,它的来源以及其他它能提供什么帮助等,那就更好了。
你的第一个目标

对于你的系统,你有很多关心的指标。但对于你的机器学习算法,通常你需要一个单一目标——你的算法“尝试”去优化的数字。指标和目标的区别是:指标是你的系统报告的任何数字。这可能重要,也可能不重要。

法则12:不要过分思考你选择直接优化的目标

你有成千上万关心的指标,这些指标也值得你去测试。但是,在机器学习过程的早期,你会发现,即使你并没有直接去优化,他们也都会上升。比如,你关心点击次数,停留时间以及每日活跃用户数。如果仅优化了点击次数,通常也会看到停留时间增加了。

所以,当提高所有的指标都不难的时候,就没必要花心思来如何权衡不同的指标。不过过犹不及:不要混淆了你的目标和系统的整体健康度。

法则13:为你的第一个目标选择一个简单、可观察以及可归因的指标

有时候你自以为你清楚真实的目标,但随着你对数据的观察,对老系统和新的机器学习系统的分析,你会发现你又想要调整。而且,不同的团队成员对于真实目标并不能达成一致。机器学习的目标必须是能很容易测量的,并且一定是“真实”目标的代言。因此,在简单的机器学习目标上训练,并创建一个“决策层”,以允许你在上面增加额外的逻辑(这些逻辑,越简单越好)来形成最后的排序。

最容易建模的是那些可以直接观察并可归属到系统的某个动作的用户行为:

1.排序的链接被点击了吗?

2.排序的物品被下载了吗?

3.排序的物品被转发/回复/邮件订阅了吗?

4.排序的物品被评价了吗?

5.展示的物品是否被标注为垃圾/色情/暴力?

最开始要避免对间接效果建模:

1.用户第2天会来访吗?

2.用户访问时间是多长?

3.每日活跃用户是什么样的?

间接效果是非常重要的指标,在A/B test和发布决定的时候可以使用。

最后,不要试图让机器学习来回答以下问题:

1.用户使用你的产品是否开心

2.用户是否有满意的体验

3.产品是否提高了用户的整体幸福感

4.这些是否影响了公司的整体健康度

这些都很重要,但太难评估了。与其如此,不如考虑其他代替的:比如,用户如果高兴,那停留时间就应该更长。如果用户满意,他就会再次造访。

法则14:从一个可解释的模型开始,使调试更容易。

线性回归,逻辑回归和泊松回归直接由概率模型激发。每个预测可解释为概率或期望值。这使得他们比那些使用目标来直接优化分类准确性和排序性能的模型要更容易调试。比如,如果训练时的概率和预测时的概率,或者生产系统上的查看到的概率有偏差,那说明存在某种问题。

比如在线性,逻辑或者泊松回归中,存在数据子集,其中平均预测期望等于平均标记(1-力矩校准或刚刚校准)。如果有一个特征对于每个样例,取值要么为1,有么为0,那为1的那些样例就是校准的。同样,如如果都为1,那所有样例都是校准的。

通常我们会使用这些概率预测来做决策:比如,按期望值(比如,点击/下载等的概率)对贴排序。但是,要记住,当到了要决定选择使用哪个模型的时候,决策就不仅仅是关于提供给模型的数据的概率性了。

法则15:在决策层区分垃圾过滤和质量排名

质量排名是一门艺术,而垃圾过滤是一场战争。那些使用你系统的人非常清楚你采用什么来评价一篇帖子的质量,所以他们会想尽办法来使得他们的帖子具有这些属性。因此,质量排序应该关注对哪些诚实发布的内容进行排序。如果将垃圾邮件排高名次,那质量排序学习器就大打折扣。同理也要将粗俗的内容从质量排序中拿出分开处理。垃圾过滤就是另外一回事。你必须考虑到要生成的特征会经常性的改变。你会输入很多明显的规则到系统中。至少要保证你的模型是每日更新的。同时,要重点考虑内容创建者的信誉问题。

机器学习阶段二:特征工程

将训练数据导入学习系统、完成相关感兴趣指标的评估记录以及搭建服务架构,这些都是机器学习系统生命周期的第一阶段非常重要的任务。当已经具有一个可工作的端对端系统,并且构建了单元测试和系统测试,那么,就进入阶段二了。

在第二阶段,有很多可以很容易就取得的成果。有很多明显能加入系统的特征。因此,在机器学习的第二阶段会涉及到导入尽可能多的特征,并且以最直观地方式组合它们。在此阶段,所有指标应该仍然在上升。将会经常性的发版。这将是一个伟大的时刻,在这个阶段能够吸引很多的工程师来融合所有想要的数据来创建一个了不起的学习系统

法则16:做好发布和迭代的计划

不要期望现在发布的这个模型是最后。因此,考虑你给当前这个模型增加的复杂度会不会减慢后续的发布。很多团队一个季度,甚至很多年才发布一个模型。以下是应该发布新模型的三个基本原因:

1.会不断出现新的特征

2..您正在以新的方式调整规则化和组合旧特征,或者

3.你正在调整目标。

无论如何,对一个模型多点投入总是好的:看看数据反馈示例可以帮助找到新的、旧的以及坏的信号。 因此,当你构建你的模型时,想想添加,删除或重组特征是不是很容易。 想想创建工作流的新副本并验证其正确性是不是很容易。 考虑是否可能有两个或三个副本并行运行。 最后,不要担心35的特征16是否会进入此版本的工作流(Finally,don’t worry about whether feature 16 of 35 makes it into this version of the pipeline.)。 这些,你都会在下个季度得到。

法则17:优先考虑哪些直接观察到和可记录的特征,而不是那些习得的特征。

首先,什么是习得特征?所谓习得特征,就是指外部系统(比如一个无监督聚类系统)生成的特征,或者是学习器自己生成的特征(比如,通过分解模型或者深度学习)。这些特征都有用,但涉及到太多问题,因此不建议在第一个模型中使用。

如果你使用外部系统来创建一个特征,切记这个系统本身是有自己目标的。而它的目标很可能和你目前的目标不相关。这个外部系统可能已经过时了。如果你从外部 系统更新特征,很可能这个特征的含义已经改变。使用外部系统提供的特征,一定要多加小心。

分解模型和深度学习模型最主要的问题是它们是非凸的。因此不能找到最优解,每次迭代找到的局部最小都不同。这种不同让人很难判断一个对系统的影响到底是有意义的,还是只是随机的。一个没有深奥特征的模型能够带来非常好的基准性能。只有当这个基准实现后,才考虑更深奥的方法。

法则18:从不同的上下文环境中提取特征

通常情况下,机器学习只占到一个大系统中的很小一部分,因此你必须要试着从不同角度审视一个用户行为。比如热门推荐这一场景,一般情况下论坛里“热门推荐”里的帖子都会有许多评论、分享和阅读量,如果利用这些统计数据对模型展开训练,然后对一个新帖子进行优化,就有可能使其成为热门帖子。另一方面,YouTube上自动播放的下一个视频也有许多选择,例如可以根据大部分用户的观看顺序推荐,或者根据用户评分推荐等。总之,如果你将一个用户行为用作模型的标记(label),那么在不同的上下文条件下审视这一行为,可能会得到更丰富的特征(feature),也就更利于模型的训练。需要注意的是这与个性化不同:个性化是确定用户是否在特定的上下文环境中喜欢某一内容,并发现哪些用户喜欢,喜欢的程度如何。

法则19:尽量选择更具体的特征

在海量数据的支持下,即使学习数百万个简单的特征也比仅仅学习几个复杂的特征要容易实现。由于被检索的文本标识与规范化的查询并不会提供太多的归一化信息,只会调整头部查询中的标记排序。因此你不必担心虽然整体的数据覆盖率高达90%以上,但针对每个特征组里的单一特征却没有多少训练数据可用的情况。另外,你也可以尝试正则化的方法来增加每个特征所对应的样例数。

法则20:以合理的方式组合、修改现有的特征

有很多组合和修改特征的方式。类似TensorFlow的机器学习系统能够通过‘transformations’(转换)来预处理数据。最基本的两种方式是:“离散化”(discretizations)和“交叉”(crosses)

离散化:将一个值为连续的特征拆分成很多独立的特征。比如年龄,1~18作为1个特征,18~35作为1个特征等等。不要过分考虑边界,通常基本的分位点就能达到最好。

交叉:合并多个特征。在TensorFlow的术语中,特征栏是一组相似的特征,比如{男性,女性},{美国,加拿大,墨西哥}等。这里的交叉是指将两个或多个特征栏合并,例如{男性,女性}×{美国,加拿大,墨西哥}的结果就是一个交叉(a cross),也就构成了一个新的特征栏。假设你利用TensorFlow框架创建了这样一个交叉,其中也就包含了{男性,加拿大}的特征,因此这一特征也就会出现在男性加拿大人的样例中。需要注意的是,交叉方法中合并的特征栏越多,所需要的训练数据量就越大。

如果通过交叉法生成的特征栏特别庞大,那么就可能引起过拟合。
例如,假设你正在进行某种搜索,并且在查询请求和文档中都具有一个包含关键字的特征栏。那么假如你选择用交叉法组合这两个特征栏,这样得到的新特征栏就会非常庞大,它内部包含了许多特征。当这种情况发生在文本搜索场景时,有两种可行的应对方法。最常用的是点乘法(dot product),点乘法最常见的处理方式就是统计查询请求和文档中共同的所有特征词,然后对特征离散化。另一个方法是交集(intersection),比如当且仅当关键词同时出现在文档和查询结果中时,我们才能获取所需的特征。

法则21:通过线性模型学到的特征权重的数目,大致与数据量成正比

许多人都认为从一千个样例中并不能得到什么可靠的训练结果,或者由于选择了某种特定的模型,就必须获取一百万个样例,否则就没法展开模型训练。这里需要指出的是,数据量的大小是和需要训练的特征数正相关的:

1) 假如你在处理一个搜索排名问题,文档和查询请求中包含了数百万个不同的关键词,并且有一千个被标记的样例,那么你应该用上文提到的点乘法处理这些特征。这样就能得到一千个样例,对应了十几个特征。

2) 如你有一百万个样例,那么通过正则化和特征选择的方式就可以交叉处理文档和查询请求中的特征栏,这可能会产生数百万的特征数,但再次使用正则化可以大大减少冗余特征。这样就可能得到一千万个样例,对应了十万个特征。

3) 如果你有数十亿或数百亿个样例,那同样可以通过特征选择或正则化的方法交叉处理文档和查询请求中的特征栏。这样就可能得到十亿个样例,对应了一千万个特征。

法则22:清理不再需要的特征

不再使用的特征,在技术上就是一个累赘。如果一个特征不再使用,并且也没办法和其他的特征组合,那就清理掉!你必须确保系统清洁,以满足能尽可能快的尝试最有希望得出结果的特征。对于那些清理掉的,如果有天需要,也可以再加回来。

至于保持和添加什么特征,权衡的一个重要指标是覆盖率。比如,如果某些特征只覆盖了8%的用户,那保留还是不保留都不会带来什么影响。

另一方面,增删特征时也要考虑其对应的数据量。例如你有一个只覆盖了1%数据的特征,但有90%的包含这一特征的样例都通过了训练,那么这就是一个很好的特征,应该添加。

对系统的人工分析

在进入机器学习第三阶段前,有一些在机器学习课程上学习不到的内容也非常值得关注:如何检测一个模型并改进它。这与其说是门科学,还不如说是一门艺术。这里再介绍几种要避免的反模式(anti-patterns)

法则23:你并不是一个典型的终端用户

这可能是让一个团队陷入困境的最简单的方法。虽然fishfooding(只在团队内部使用原型)和dogfooding(只在公司内部使用原型)都有许多优点,但无论哪一种,开发者都应该首先确认这种方式是否符合性能要求。要避免使用一个明显不好的改变,同时,任何看起来合理的产品策略也应该进一步的测试,不管是通过让非专业人士来回答问题,还是通过一个队真实用户的线上实验。这样做的原因主要有两点:

首先,你离实现的代码太近了。你只会看到帖子的特定的一面,或者你很容易受到情感影响(比如,认知性偏差)。

其次,作为开发工程师,时间太宝贵。并且有时候还没什么效果。

如果你真的想要获取用户反馈,那么应该采用用户体验法(user experience methodologies)。在流程早期创建用户角色(详情见Bill Buxton的《Designing User ExperienCES》一书),然后进行可用性测试(详情见Steve Krug的《Do not Make Me Think》一书)。这里的用户角色涉及创建假想用户。例如,如果你的团队都是男性,那设计一个35岁的女性用户角色所带来的效果要比设计几个25~40岁的男性用户的效果强很多。当然,让用户实测产品并观察他们的反应也是很不错的方法。

法则24:测量模型间的差异

在将你的模型发布上线前,一个最简单,有时也是最有效的测试是比较你当前的模型和已经交付的模型生产的结果之间的差异。如果差异很小,那不再需要做实验,你也知道你这个模型不会带来什么改变。如果差异很大,那就要继续确定这种改变是不是好的。检查对等差分很大的查询能帮助理解改变的性质(是变好,还是变坏)。但是,前提是一定要确保你的系统是稳定的。确保一个模型和它本身比较,这个差异很小(理想情况应该是无任何差异)。

法则25:选择模型的时候,实用的性能要比预测能力更重要

你可能会用你的模型来预测点击率(CTR)。当最终的关键问题是你要使用你的预测的场景。如果你用来对文本排序,那最终排序的质量可不仅仅是预测本身。如果你用来排查垃圾文件,那预测的精度显然更重要。大多数情况下,这两类功能应该是一致的,如果他们存在不一致,则意味着系统可能存在某种小增益。因此,假如一个改进措施可以解决日志丢失的问题,但却造成了系统性能的下降,那就不要采用它。当这种情况频繁发生时,通常应该重新审视你的建模目标。

法则26:从误差中查找新模式、创建新特征

假设你的模型在某个样例中预测错误。在分类任务中,这可能是误报或漏报。在排名任务中,这可能是一个正向判断弱于逆向判断的组。但更重要的是,在这个样例中机器学习系统知道它错了,需要修正。如果你此时给模型一个允许它修复的特征,那么模型将尝试自行修复这个错误。

另一方面,如果你尝试基于未出错的样例创建特征,那么该特征将很可能被系统忽略。例如,假设在谷歌Play商店的应用搜索中,有人搜索“免费游戏”,但其中一个排名靠前的搜索结果却是一款其他App,所以你为其他App创建了一个特征。但如果你将其他App的安装数最大化,即人们在搜索免费游戏时安装了其他App,那么这个其他App的特征就不会产生其应有的效果。

所以,正确的做法是一旦出现样例错误,那么应该在当前的特征集之外寻找解决方案。例如,如果你的系统降低了内容较长的帖子的排名,那就应该普遍增加帖子的长度。而且也不要拘泥于太具体的细节。例如你要增加帖子的长度,就不要猜测长度的具体含义,而应该直接添加几个相关的特征,交给模型自行处理,这才是最简单有效的方法。

法则27:尝试量化观察到的异常行为

有时候团队成员会对一些没有被现有的损失函数覆盖的系统属性感到无能为力,但这时抱怨是没用的,而是应该尽一切努力将抱怨转换成实实在在的数字。比如,如果应用检索展示了太多的不好应用,那就应该考虑人工评审来识别这些应用。如果问题可以量化,接下来就可以将其用作特征、目标或者指标。总之,先量化,再优化

法则28:注意短期行为和长期行为的差别

假设你有一个新系统,它可以查看每个doc_id和exact_query,然后根据每个文档的每次查询行为计算其点击率。你发现它的行为几乎与当前系统的并行和A/B测试结果完全相同,而且它很简单,于是你启动了这个系统。却没有新的应用显示,为什么?由于你的系统只基于自己的历史查询记录显示文档,所以不知道应该显示一个新的文档。
要了解一个系统在长期行为中如何工作的唯一办法,就是让它只基于当前的模型数据展开训练。这一点非常困难。
离线训练和实际线上服务间的偏差

引起这种偏差的原因有:

1)训练工作流和服务工作流处理数据的方式不一样;

2)训练和服务使用的数据不同;

3)算法和模型间循的一个循环反馈。

法则29:确保训练和实际服务接近的最好方式是保存服务时间时使用到的那些特征,然后在后续的训练中采用这些特征

即使你不能对每个样例都这样做,做一小部分也比什么也不做好,这样你就可以验证服务和训练之间的一致性(见规则37)。在谷歌采取了这项措施的团队有时候会对其效果感到惊讶。比如YouTube主页在服务时会切换到日志记录特征,这不仅大大提高了服务质量,而且减少了代码复杂度。目前有许多团队都已经在其基础设施上采用了这种策略。

法则30:给抽样数据按重要性赋权重,不要随意丢弃它们

当数据太多的时候,总会忍不住想要丢弃一些,以减轻负担。这绝对是个错误。有好几个团队就因为这样,而引起了不少问题(见规则6)。尽管那些从来没有展示给用户的数据的确可以丢弃,但对于其他的数据,最好还是对重要性赋权。比如如果你绝对以30%的概率对样例X抽样,那最后给它一个10/3的权重。使用重要性加权并不影响规则14中讨论的校准属性。

法则31:注意在训练和服务时都会使用的表中的数据是可能变化的

因为表中的特征可能会改变,在训练时和服务时的值不一样,这会造成,哪怕对于相同的文章,你的模型在训练时预测的结果和服务时预测的结果都会不一样。避免这类问题最简单的方式是在服务时将特征写入日志(参阅法则32)。如果表的数据变化的缓慢,你也可以通过每小时或者每天给表建快照的方式来保证尽可能接近的数据。但这也不能完全解决这种问题。

法则32:尽量在训练工作流和服务工作流间重用代码

首先需要明确一点:批处理和在线处理并不一样。在线处理中,你必须及时处理每一个请求(比如,必须为每个查询单独查找),而批处理,你可以合并完成。服务时,你要做的是在线处理,而训练是批处理任务。尽管如此,还是有很多可以重用代码的地方。比如说,你可以创建特定于系统的对象,其中的所有联结和查询结果都以人类可读的方式存储,错误也可以被简单地测试。然后,一旦在服务或训练期间收集了所有信息,你就可以通过一种通用方法在这个特定对象和机器学习系统需要的格式之间形成互通,训练和服务的偏差也得以消除。因此,尽量不要在训练时和服务时使用不同的变成语言,毕竟这样会让你没法重用代码。

法则33:训练采用的数据和测试采用的数据不同(比如,按时间上,如果你用1月5日前的所有的数据训练,那测试数据应该用1月6日及之后的)

通常,在评测你的模型的时候,采用你训练时用的数据之后生成的数据能更好反映实际线上的结果。因为可能存在每日效应(daily effects),你可能没有预测实际的点击率和转化率。但AUC应该是接近的。

法则34:在二进制分类过滤的应用场景中(例如垃圾邮件检测),不要为了纯净的数据做太大的性能牺牲

一般在过滤应用场景中,反面样例并不会对用户展示。不过假如你的过滤器在服务过程中阻止了75%的反面样例,那么你可能需要从向用户显示的实例中提取额外的训练数据并展开训练。比如说,用户将系统认可的邮件标记为垃圾邮件,那么你可能就需要从中学习。

但这种方法同时也引入了采样偏差。如果改为在服务期间将所有流量的1%标记为“暂停”,并将所有这样的样例发送给用户,那你就能收集更纯净的数据。现在你的过滤器阻止了至少74%的反面样例,这些样例可以成为训练数据。

需要注意的是,如果你的过滤器阻止了95%或更多的反面样例,那这种方法可能就不太适用。不过即使如此,如果你想衡量服务的性能,可以选择做出更细致的采样(例如0.1%或0.001%),一万个例子足以准确地估计性能。

法则35:注意排序问题的固有偏差

当你彻底改变排序算法时,一方面会引起完全不同的排序结果,另一方面也可能在很大程度上改变算法未来可能要处理的数据。这会引入一些固有偏差,因此你必须事先充分认识到这一点。以下这些方法可以有效帮你优化训练数据。

1.对涵盖更多查询的特征进行更高的正则化,而不是那些只覆盖单一查询的特征。这种方式使得模型更偏好那些针对个别查询的特征,而不是那些能够泛化到全部查询的特征。这种方式能够帮助阻止非常流行的结果进入不相关查询。这点和更传统的建议不一样,传统建议应该对更独特的特征集进行更高的正则化。

2.只允许特征具有正向权重,这样一来就能保证任何好特征都会比未知特征合适。

3.不要有那些仅仅偏文档(document-only)的特征。这是法则1的极端版本。比如,不管搜索请求是什么,即使一个给定的应用程序是当前的热门下载,你也不会想在所有地方都显示它。没有仅仅偏文档类特征,这会很容易实现。

法则36:避免具有位置特征的反馈回路

内容的位置会显著影响用户与它交互的可能性。很明显,如果你把一个App置顶,那它一定会更频繁地被点击。处理这类问题的一个有效方法是加入位置特征,即关于页面中的内容的位置特征。假如你用位置类特征训练模型,那模型就会更偏向“1st-position”这类的特征。因而对于那些“1st-position”是True的样例的其他因子(特征),你的模型会赋予更低的权重。而在服务的时候,你不会给任何实体位置特征,或者你会给他们所有相同的默认特征。因为在你决定按什么顺序排序展示前,你已经给定了候选集。

切记,将任何位置特征和模型的其他特征保持一定的分离是非常重要的。因为位置特征在训练和测试时不一样。理想的模型是位置特征函数和其他特征的函数的和。比如,不要将位置特征和文本特征交叉。

法则37:测量训练/服务偏差

很多情况会引起偏差。大致上分为一些几种:

1.训练数据和测试数据的性能之间的差异。一般来说,这总是存在的,但并不总是坏事。

2.测试数据和新时间生成数据之间的性能差异。同样,这也总是存在的。你应该调整正则化来最大化新时间数据上的性能。但是,如果这种性能差异很大,那可能说明采用了一些时间敏感性的特征,且模型的性能下降了。

3.新时间数据和线上数据上的性能差异。如果你将模型应用于训练数据的样例,也应用于相同的服务样例,则它们应该给出完全相同的结果(详见规则5)。因此,如果出现这个差异可能意味着出现了工程上的异常。
机器学习第三阶段

有一些信息暗示第二阶段已经结束。首先,月增长开始减弱。你开始要考虑在一些指标间权衡:在某些测试中,一些指标增长了,而有些却下降了。这将会变得越来越有趣。增长越来越难实现,必须要考虑更加复杂的机器学习。

警告:相对于前面两个阶段,这部分会有很多开放式的法则。第一阶段和第二阶段的机器学习总是快乐的。当到了第三阶段,团队就不能不去找到他们自己的途径了。

法则38:如果目标不协调,并成为问题,就不要在新特征上浪费时间

当达到度量瓶颈,你的团队开始关注 ML 系统目标范围之外的问题。如同之前提到的,如果产品目标没有包括在算法目标之内,你就得修改其中一个。比如说,你也许优化的是点击数、点赞或者下载量,但发布决策还是依赖于人类评估者。

法则39:模型发布决策是长期产品目标的代理

艾丽斯有一个降低安装预测逻辑损失的想法。她增加了一个特征,然后逻辑损失下降了。当线上测试的时候,她看到实际的安装率增加了。但当她召集发布复盘会议时,有人指出每日活跃用户数下降了5%。于是团队决定不发布该模型。艾丽斯很失望,但意识到发布决策依赖于多个指标,而仅仅只有一些是机器学习能够直接优化的。

真实的世界不是网络游戏:这里没有“攻击值”和“血量”来衡量你的产品的健康状况。团队只能靠收集统计数据来有效的预测系统在将来会如何。他们必须关心用户粘性、1 DAU,30 DAU,收入以及广告主的利益。这些 A/B 测试中的指标,实际上只是长期目标的代理:让用户满意、增加用户、让合作方满意还有利润;即便这时你还可以考虑高品质、有使用价值的产品的代理,以及五年后一个繁荣的企业的代理。

做出发布决策唯一容易的是当所有指标都变好的时候(或者至少没有变化)。当团队在复杂 ML 算法和简单启发式算法之间有选择时;如果简单的启发式算法在这些指标上做得更好;那么应当选择启发式。另外,所有指标数值并没有明确的孰重孰轻。考虑以下更具体的两种情形:

如果现有系统是 A ,团队不会想要转移到 B。如果现有系统是 B,团队也不会想要转到 A。这看起来与理性决策相抵触:但是,对指标变化的预期情形或许会发生,或许不会。因此任意一种改变都有相当大的风险。每一个指标覆盖了一些团队所关注的风险。但没有指标能覆盖团队的首要关切——“我的产品在五年后会怎样?”

另一方面,个体更倾向于那些他们能够直接优化的单一目标。大多数机器学习工具也如此。在这样的环境下,一个能够创造新特征的工程师总能够稳定的输出产品发布。有一种叫做多目标学习的机器学习类型开始处理这类问题。比如,给每个目标设定最低界限,然后优化指标的线性组合。但即便如此,也不是所有指标都能轻易表达为 ML 目标:如果一篇文章被点击了,或者一个app被安装了,这可能是只是因为这个内容被展示了。但要想搞清楚为什么一个用户访问你的网站就更难了。如何完整预测一个网站将来是否能成功是一个AI完全(AI-complete)问题。就和计算机视觉或者自然语言处理一样难。

法则40:保证集成模型(ensemble)的简洁

接收原始特征、直接对内容排序的统一模型,是最容易理解、最容易修补漏洞的模型。但是,一个集成模型(一个把其他模型得分组合在一起的“模型”)的效果会更好。为保持简洁,每个模型应该要么是一个只接收其他模型的输入的集成模型,要么是一个有多种特征的基础模型,但不能两者皆是。如果你有单独训练、基于其它模型的模型,把它们组合到一起会导致不好的行为。

只使用简单模型来集成那些仅仅把你的基础模型输出当做输入。你同样想要给这些集成模型加上属性。比如,基础模型生成得分的提高,不应该降低集成模型的分数。另外,如果连入模型在语义上可解释(比如校准了的)就最好了,这样其下层模型的改变不会影响集成模型。此外,强行让下层分类器预测的概率升高,不会降低集成模型的预测概率。

法则41:当碰到性能瓶颈,与其精炼已有的信息,不如寻找有质量的新信息源

你已经给用户增加了人工统计属性信息,给文本中的词增加了一些信息,经历了模板探索并且实施了正则化。然后,几乎有好几个季度你的关键指标都没有过提高超过1%了。现在该怎么办?

现在是到了为完全不同的特征(比如,用户昨天,上周或者去年访问过的文档,或者来自不同属性的数据)构建基础架构的时候了。为你的公司使用维基数据(wikidata)实体或者一些内部的东西(比如谷歌的知识图,Google’s knowledge graph)。你或许需要使用深度学习。开始调整你对投资回报的期望,并作出相应努力。如同所有工程项目,你需要平衡新增加的特征与提高的复杂度。

法则42:不要期望多样性、个性化、相关性和受欢迎程度之间有紧密联系

一系列内容的多样性能意味着许多东西,内容来源的多样性最为普遍。个性化意味着每个用户都能获得它自己感兴趣的结果。相关性意味着一个特定的查询对于某个查询总比其他更合适。显然,这三个属性的定义和标准都不相同。

问题是标准很难打破。

注意:如果你的系统在统计点击量、耗费时间、浏览数、点赞数、分享数等等,你事实上在衡量内容的受欢迎程度。有团队试图学习具备多样性的个性化模型。为个性化,他们加入允许系统进行个性化的特征(有的特征代表用户兴趣),或者加入多样性(表示该文档与其它返回文档有相同特征的特征,比如作者和内容),然后发现这些特征比他们预想的得到更低的权重(有时是不同的信号)。

这不意味着多样性、个性化和相关性就不重要。就像之前的规则指出的,你可以通过后处理来增加多样性或者相关性。如果你看到更长远的目标增长了,那至少你可以声称,除了受欢迎度,多样性/相关性是有价值的。你可以继续使用后处理,或者你也可以基于多样性或相关性直接修改你的目标。

法则43:不同产品中,你的朋友总是同一个,你的兴趣不会如此

谷歌的 ML 团队 常常把一个预测某产品联系紧密程度(the closeness of a connection in one product)的模型,应用在另一个产品上,然后发现效果很好。另一方面,我见过好几个在产品线的个性化特征上苦苦挣扎的团队。是的,之前看起来它应该能奏效。但现在看来它不会了。有时候起作用的是——用某属性的原始数据来预测另一个属性的行为。即便知道某用户存在另一个属性能凑效的历史,也要记住这一点。比如说,两个产品上用户活动的存在或许就自身说明了问题。




你可能感兴趣的:(机器学习最佳实践,Google机器学习43条军规:)