论文地址:广告点击预测:从战壕中看-McMahan等人。2013年

    昨天我们分析了技术债务可以潜入机器学习系统的许多方面。在那篇论文中,作者提到了一个自动化的功能管理工具,自从它被采用以来,“它经常允许谷歌的一个团队每季度安全地删除数千行与功能相关的代码,并自动验证版本和其他问题。该系统在很多情况下都防止了在新模型中意外使用被弃用或损坏的功能。“今天的选择是‘广告点击预测:从战壕中观看’是谷歌的一篇论文,它进一步深入了解了该工具,以及其他一些实用的工具和技术,团队使用具有数十亿特性的模型进行大规模机器学习。

    视觉探索
    大规模学习中的一个潜在陷阱是,聚合性能指标可能隐藏特定于某些数据子总体的影响。例如,在一个度量上获得的小的聚合精度可能实际上是由不同国家或特定查询主题的正负变化混合引起的。这使得不仅要在汇总数据上提供绩效指标,而且还要在各种数据片段上提供绩效指标,例如每个国家或每个主题的绩效指标。因为有数百种方法可以有意义地对数据进行切片,所以我们必须能够有效地检查数据的可视化摘要。为此,我们开发了一种称为GridViz的高维交互式可视化,以便全面了解模型性能。

    这是GridViz的屏幕截图,它将三个变量与一个控制模型进行了比较。
    ad-click-prediction.png

    该工具允许交互式探索,“总体而言,它使我们能够显著提高对各种数据子集上模型性能的理解深度,并确定需要改进的高影响区域。”

    自动化功能管理
    可伸缩机器学习的一个重要方面是管理安装的规模,包括构成机器学习系统的所有配置、开发人员、代码和计算资源。一个由多个团队组成的安装需要一些开销来建模几十个特定于领域的问题。一个特别有趣的例子是机器学习的特征空间管理。我们可以将特征空间描述为一组上下文和语义信号,其中每个信号(例如,“广告中的单词”、“原产国”等)都可以转换为一组真正有价值的特征以供学习。在大型安装中,许多开发人员可能在信号开发上异步工作。

    信号可能有许多不同的版本,并且通常由开发它们的团队以外的团队使用。如果没有某种方法来跟踪所有这些,一旦你接触到成千上万的信号和数百个模型(可能在那之前的某个时间;),事情就会开始失控…。

    为了处理用例的组合增长,我们部署了一个元数据索引,用于管理数百个活动模型对数千个输入信号的消耗。索引信号是针对各种关注点手动和自动添加注释的;示例包括不推荐、特定于平台的可用性和特定于域的适用性。新模型和活动模型所消耗的信号由自动警报系统进行审查。不同的学习平台共享一个公共接口,用于向中心索引报告信号消耗。当一个信号被弃用时(例如当一个新的版本可用时),我们可以快速识别该信号的所有使用者并跟踪替换工作。当信号的改进版本可用时,可以提醒消费者尝试新版本。
    (与典型的pub-sub系统相比,这个索引只维护发布者和订阅者的元数据,我的理解是实际的信号消耗是独立发生的)。
    新信号通过自动测试进行审查,旧信号自动指定用于代码清理和删除相关数据。

    有效的自动化信号消耗管理可确保在第一次正确完成更多学习。这减少了浪费和重复的工程工作,节省了许多工程时间。在运行学习算法之前验证配置的正确性可以消除许多可能导致模型不可用的情况,从而节省大量潜在的资源浪费。

    对于任何一家将“数据驱动”方法放在心上的合理规模的公司来说,这种信号生成和消费与元数据跟踪的脱钩,可以管理信号生命周期和消费,在我看来,这是你应该考虑的核心能力。

    使用大型模型的策略和策略
    现在让我们稍微改变一下策略,看看Google广告点击率(ML)团队用来处理非常大的数据集和非常大的模型的一些策略。

    对于大规模学习,广义线性模型(如logistic回归)的在线算法具有许多优点。尽管特征向量x可能有数十亿个维度,但通常每个实例只有数百个非零值。由于每个训练示例只需考虑一次,因此通过从磁盘或通过网络流式传输示例,可以在大型数据集上进行有效的训练。

    一个在线梯度下降(OGD)模型产生一个权重向量w。给定数十亿个特征,这本身就是一个有效管理的挑战。模型可以稀疏存储,因此w中非零系数的数目决定了内存的使用。“不幸的是,OGD并不特别擅长生成稀疏模型。”一旦这种内存使用成为一个问题,就可以使用其他算法。团队决定“跟随(近似)正则化的领导者”(FTRL noximal)–论文展示了算法的细节,这里我更感兴趣的是模型大小可能是一个问题的简单想法。与FTRL近端相比,OGD具有两倍多的非零系数,但是FTRL近端和OGD具有与“AucLoss”(1-曲线下面积)非常相似的性能。

    当然,在训练过程中, 内存也是一个问题:

    在许多具有高维数据的领域中,绝大多数特征极其罕见。事实上,在我们的一些模型中,一半的独特功能只在整个数十亿个示例的训练集中出现一次。跟踪这些罕见的特性的统计数据是很昂贵的,这些特性永远不会有任何实际用途。不幸的是,我们不知道哪些功能将是罕见的…

    作者为他们的用例找到的最有效的机制是Bloom过滤器包含。这项工作只包括在模型中的功能,一旦他们已经看到了一定的次数…

    我们使用一组滚动计数的Bloom过滤器来检测训练中遇到的前n个特征。一旦一个特征出现超过n次(根据过滤器),我们将其添加到模型中,并在随后的观察中使用它进行训练,如上所述。注意,这种方法也是概率的,因为计数bloom过滤器能够产生假阳性(但不能产生假阴性)。也就是说,我们有时会包含一个实际发生不到n次的特性。

    在n=2的情况下使用Bloom Filter Inclusion可以节省66%的RAM,而aucross的损失仅为0.008%。

    另一个直接的内存节省是通过意识到在他们的模型中几乎所有的系数值都在范围(-2,2)内找到的。因此,使用32位或64位浮点在所需的精度级别上是过分的。通过切换到16位表示,并添加一个简单的随机舍入策略以减少舍入误差的累积,作者设法将RAM对系数存储的要求降低了75%。

    对于训练数据集本身的大小可以做些什么?如果我们能用更少的训练数据得到可比的准确度结果呢?如果是,我们应该如何选择合适的子集?作者通过在他们的用例中仔细利用训练数据的性质,找到了回答这些问题的方法:

    典型的点击率(CTRs)远低于50%,这意味着积极的例子(点击)相对较少。因此,简单的统计计算表明点击在学习CTR估计方面相对更有价值。我们可以利用这一点来显著减少训练数据的大小,同时将对准确性的影响降到最低。

    作者在训练数据中包括

    • 任何至少点击了一个广告的查询,以及
    • 未点击广告的查询的分数r∈(0.1)。

    当然,对这些子样本数据进行天真的训练会导致严重的预测偏差。通过给每个示例分配一个重要权重ωt,很容易解决这个问题,其中,如果事件t在单击的查询中,则ωt=1,否则为1/r。由于我们控制了抽样分布,因此不必像一般的抽样选择那样估计权重ω。
    实验表明,即使是非点击查询的相当积极的子抽样对模型性能的影响也很小,而且对r的特定值也不是特别敏感。
    为了同时试验大量的模型变体,作者还介绍了一些他们用来节省空间的技术。这涉及到同时训练模型和尽可能多地共享数据。对于非常大的模型集,甚至系数都是共享的!对于每个特征i,使用i的每个模型都会计算系数的新值。然后对这些值进行平均,以生成下一次迭代的新系数值。

    我们怎么知道它起作用了?
    由于不同的度量以不同的方式响应模型更改,我们发现在多个可能的性能度量中评估模型更改通常是有用的。我们计算诸如aucross(即1-AUC,其中AUC是ROC曲线度量下的标准面积)、LogLoss(见等式(1))和SquaredError等度量。为了保持一致性,我们还设计了度量标准,以便较小的值总是更好的。

    谷歌的团队发现,相对于一些基线模型,相对变化(用百分比表示)给出了更好的直觉,而不是专注于绝对的度量值:

    绝对度量值通常是误导性的。即使预测是完美的,LogLoss和其他度量也会因问题的难度(即Bayes风险)而有所不同。如果点击率接近50%,则最佳可实现的LogLoss比点击率接近2%时高得多。这一点很重要,因为点击率因国家和查询而异,因此平均值在一天内变化。因此我们总是看
    相对变化,通常表示为度量相对于基线模型的百分比变化。根据我们的经验,随着时间的推移,相对变化要稳定得多。
    我发现另一个有趣的技术是团队将模型预测的现场校准与模型本身的开发和训练分离开来的方式。系统偏差反映了在某些数据切片上预测的平均CTR和实际CTR之间的差异。它可能由于许多原因潜入系统,包括不准确的建模假设、学习算法的缺陷以及在训练或预测服务时间不可用的隐藏特征。
    为了解决这个问题,我们可以使用一个校准层来匹配预测的点击率和观察到的点击率。我们的预测是在一片数据d上校准的,如果当我们预测p时,实际观测的CTR接近p。我们可以通过应用校正函数τd(p)来改进校准,其中p是预测的CTR,d是训练数据分区的元素。我们将成功定义为在数据的各种可能分区上给出经过良好校准的预测。

    总结如果您在生产环境中使用的是非常大的模型和培训集,希望本文能给您一些灵感,让您在一些地方寻找更易于管理/高效的方法。不管您使用的模型和/或数据有多大,如果您在组织内认真对待机器学习,您可能需要考虑一些实用的建议:

    • 管理信号发布者和使用者的自动化功能管理系统。
    • 用于可视化和比较建议的模型更改的影响的工具
    • 监测多个指标并将相对变化与基线进行比较
    • 一种独立于模型的系统偏差测量与校正系统
    • 当系统采取的操作数超过某个阈值时发出警报(此建议实际上来自昨天的论文)。