为了让模型迭代过程更加可操作,并能够提供更多的信息,Uber 开发了一个用于机器学习性能诊断和模型调试的可视化工具——Manifold。
机器学习在 Uber 平台上得到了广泛的应用,以支持智能决策制定和特征预测(如 ETA 预测 及 欺诈检测)。为了获得最佳结果,我们在开发精准预测机器学习模型上投入了大量资源。事实上,对从业者来说,他们通常把 20% 的精力放在构建初始的工作模型上,而把 80% 的精力用来提高模型性能,这就是所谓的机器学习模型开发 20/80 分配法则。
传统上,数据科学家在开发模型时会使用汇总分数,如 对数损失、曲线下面积(area under curve,简称 AUC) 和 平均绝对误差(mean absolute error,简称 MAE) 来评估每个候选模型。尽管这些指标提供了有关模型执行情况的见解,但是,它们没有传达很多关于模型为什么表现不佳以及如何提高其性能的信息。因而,模型构建者倾向于依赖反复试验和误差来决定如何改善模型。
为了让模型迭代过程更加可操作,并能够提供更多的信息,我们开发了 Manifold(https://arxiv.org/pdf/1808.00196.pdf)。它是一个用于机器学习性能诊断和模型调试的可视化工具。Manifold 利用可视化分析技术让机器学习从业者能够超越总体指标检测模型没能精准预测的数据子集。Manifold 还通过揭示性能表现较好和较差数据子集之间的特征分布差异来说明模型性能表现不佳的潜在原因。此外,它还可以揭示对于每一个数据子集,一些候选模型将有怎样的预测准确性差异,从而为一些高级处理(如模型集成)提供根据。
在本文中,我们将介绍 Manifold 的算法和可视化设计,以及 Uber 是如何利用这工具来获得模型见解以及提高模型的性能。
Manifold 背后的动机
鉴于其复杂性,机器学习模型本质上是不透明的。随着机器学习越来越成为 Uber 业务不可分割的部分,我们需要为用户提供工具,使模型更透明且易于理解。只有这样,他们才能自信自如地使用机器学习生成的预测,而新兴的机器学习可视化可以解决这个问题。
以前的机器学习可视化方法通常包括直接可视化内部结构或模型参数和受底层算法约束的设计(导致无法扩展到可以处理公司范围内的通用用例)。
为了应对 Uber 面临的这个挑战,我们构建了 Manifold 来提供机器学习模型服务,并从分类和回归模型开始。Manifold 通过揭示数据子集之间的特征分布差异为机器学习模型开发黑盒提供了更高的透明度。
借助 Manifold 的设计,我们颠覆了传统机器学习模型的可视化。我们不检查模型,而是通过以下方式检查各个数据点:
识别影响模型性能的数据段,以及这些数据如何影响模型的性能;
评估这些数据段的聚合特征,以便识别某些模型行为背后的原因。
这个方法有助于实现模型无关性,这是在识别模型集成机会时特别有用的功能。
可视化和工作流设计
除了在《Manifold: A Model-Agnostic Framework for Interpretation and Diagnosis of Machine Learning Models》一文中所描述的研究原型之外,我们专注于揭示大量高维 ML 数据集中的重要信号和模式。在以下部分中,我们将讨论 Manifold 的界面和用户工作流,深入介绍我们的设计考虑事项,并解释支持此类可视化分析的算法。
Manifold 的界面由两个可视化部分组成:
- 性能比较视图,由小提琴编码的多路图组成,用于比较模型和数据段之间的性能。
- 特征属性视图,由两套特征分布直方图构成,用于比较两个选定数据段的特征。
Manifold 通过以下三个步骤帮助用户发现模型需要改进的区域:
- 比较:首先,给定一个具有一个或多个机器学习模型输出的数据集,Manifold 比较并突出显示模型或数据子集之间的性能差异(图 3a)。
- 切片:该步骤允许用户根据模型性能选择感兴趣的数据子集以便进行进一步的检查(图 3b)。
- 属性:然后,Manifold 突出显示所选数据子集之间的特征分布差异,帮助用户找到性能结果背后的原因(图 3c)。
我们使用 Manifold 比较模型在不同数据点(也即特征值)上的表现。作为设计替代方案,该可视化的直接实现如下图(图 4)所示:
在图 4 中,图中的每个点代表模型 x 在数据点 y 上的性能。尽管在理论上这个概念是成立的,但实际上,该方法存在 3 个主要挑战:
因为有太多的点,无法清楚地识别模式;需要通过抽离或减少点来揭示模式。
难以确定哪些特征对于 y 轴最有价值,以便识别出相关模式。
随着模型数量的增加,不同模型之间的比较变得更难。
为了提前解决这些问题,我们实现了一些聚合 / 简化操作。我们不单独表示每个数据点,而是把它们组成子集。我们没有使用 y 轴来编码特定特征的值,而是使用了表示不同数据子集的分类轴。该方法演变成我们最终的性能图表,带来了以下两个好处:
基本相似的数据点不会重复出现在图表上,只突出显示最主要的高层差异。
因为减少了图表中各种形状的数量,可以在同一图表中绘制不同的模型,以更好地加以比较。
在该工具的性能比较视图中揭示模式的关键在于把测试数据集分成子集。在 Manifold 中,数据子集是基于一个或多个性能列的聚类算法自动生成的。这样,对于每个模型,具有相似性能的数据被分到同一个组中(因为该算法确保模型 X 的性能对于子集 Y 中不同的数据点是一致的)。图 5 和图 6 说明了这个过程:
Manifold 的架构
由于生成 Manifold 可视化涉及一些密集的数值计算(聚类、KL 发散),计算性能不足会拖慢用户界面的渲染,影响到整个用户体验。因此,我们开始使用 Python,利用 Python 的 DataFrame 处理和机器学习库(如 Pandas 和 Scikit-Learn)实现所有重量级的计算。
但是,不得不依赖 Python 后端降低了 Manifold 的灵活性,难以进行组件化,在将 Manifold 和 Uber 的机器学习生态系统(比如我们的机器学习平台 Michelangelo)集成时,这成了一个缺点。因此,除了 Python 计算外,我们用 GPU 加速器添加了第 2 个用户工作流,该 GPU 加速器完全是用更加灵活的 JavaScript 编写的。
图 7 描述了这两个工作流是如何和 Manifold 集成的。
对用户来说,Manifold 的使用方式有 2 种:通过 Python 包或 npm 包(通过网页)。由于代码可重用性和模块化对两个工作流的共存至关重要,因此,Python 和 JavaScript 代码库被组织成 3 个不同的功能模块:
数据转换器,一种将来自其他内部服务(如 Michelangelo)的数据格式转换为 Manifold 内部数据表示格式的功能;
计算引擎,一种负责运行聚类和其他数据密集计算的功能;
前端组件,Manifold 可视化分析系统(其 Python 包使用了 JavaScript 前端组件的内置版本)的用户界面。
与 Python 不同,处理数据密集计算对我们的 JavaScript 计算引擎来说是个挑战。为了让用户看到有意义的模式,需要大约计算 1 万个数据记录(“行”)。除了其他操作,KL 发散的聚类和计算需要在前端进行,可能会造成速度瓶颈,严重影响用户体验。事实上,根据我们的经验,每次用户更新性能比较视图中的簇数量时,使用纯 JavaScript 实现的计算可能需要 10 多秒时间。
相反,我们把 TensorFlow.js 作为线性代数实用库来实现我们的 k 均值聚类和 KL 发散计算。因为这种类型的计算可以被矢量化,因而可以利用 WebGL 加速,所以更新同样数量的簇的任务可以在不到 1 秒的时间里完成,超过原来性能的 100 倍。
通过组件化并将其包含在 npm 包中,Manifold 具有更好的灵活性,既可以用作独立服务,也可以集成到公司的其他机器学习系统(如 Michelangelo)中。因为大多数用于机器学习的可视化工具需要额外的计算处理,超过了模型训练后端具备的计算处理能力,所以,把它们与企业机器学习系统集成在一起可能很麻烦,而且不可扩展。Manifold 针对这种情况提出了解决方案,通过在可视化分析系统中分开处理训练模型所需的计算,可以进行更快的迭代,并得到了更干净的数据接口。
Manifold 在 Uber 的使用情况
在 Uber,各个专注于机器学习的团队利用 Manifold 来处理所有事情,从 ETA 预测 到更好地理解驾驶员安全模型。下面,我们介绍最常见的两个用例:识别机器学习模型的有用特征和消除模型结果中的假阴性。在这些示例中,Manifold 让数据科学家能够发现引导他们完成模型迭代过程的见解。
识别有用的特征
Uber Eats 团队使用 Manifold 来评估 订单交付时间 预测 模型 的效果。在模型迭代过程中,他们集成了一组附加的特征,他们认为这些特征具有提高现有模型性能的潜力。但是,在他们集成了这些特征之后,模型的整体性能几乎没有改变。为什么这些新特征没有帮助?他们是否应该放弃使用这些特征的想法,还是这个低于标准的性能可以归咎于其他因素?
为了回答这些问题,他们使用了图 8 所示的模型,其中初始模型(绿色)和用附加特征训练过的模型(橙色)作为 Manifold 的输入。这两个模型的所有其他方面是相同的。
图 8 描述了通过 Manifold 数据可视化来表示的分析结果。如图所示,该测试数据集根据数据点中的性能相似性自动分为 4 个簇。对于簇 0、1 和 2,具有附加特征的模型没有提高性能。但是,在簇 3 中,新模型(具有附加特征的那个)的性能稍微好了一点,因为对数损失向左移动了一点。
由于最初的模型对簇 3 数据段的预测效果很糟糕,(对数损失比其他 3 个簇更高),我们认为对他们的模型来说,这些特征是有价值的,因为它们似乎解决了一些最难的个案。
消除假阴性
在另一个例子中,Uber 的安全团队利用 Manifold 提高了一个 二元分类 模型的性能,该模型可以识别可能发生安全事故的行程。具体地说,他们希望消除模型生成的假阴性的数量(应该预测为具有阳性标签的实例,但是模型未能捕捉到)。为此,他们需要确定在这些情形下,模型将阳性实例预测为阴性的原因。
为了实现这个目的,他们在测试数据集中过滤掉所有标记为阴性的实例,然后与标记为阳性的实例之间进行对比。他们把性能比较图表中的 x 轴度量设置为“实际预测得分”,增加了簇数量,并比较那些值低于或高于决策阈值的子集,如图 9 所示:
结果,我们注意到有几个特征(A、B、C、D、E)显示了真阳性组(灰色)和假阴性组(粉色)之间的分布差异,如图 10 所示。换句话说,如果数据点在特征 A、B、C 或 D 上的值比较低,且其真实的标签是阳性,那么该模型往往不能正确地预测 E 的值。
为了进一步深入研究这些假阴性形成的根本原因,我们直接比较了阳性组和阴性组的特征分布,如图 11 所示:
我们注意到大多数真阴性实例在特征 A、B、C 或 D 上也往往具有较低的值。因此,如果实例在这些特征上具有较低的值,那么该模型倾向于将它们预测为阴性(有时这是错的!)。在用 Manifold 进行了分析后,他们意识到该模型对这些特征索引过度。为了提高性能,他们要么找到更多能够有助于区分假阴性和真阴性的特征,要么为低于某个阈值的数据分区单独训练模型。
接下来的工作
自从 2018 年 8 月推出 Manifold 以来,该工具已经成为 Uber 机器学习开发过程的不可或缺的组成部分。Manifold 有 3 个主要优势:
模型无关性;
模型性能评估的可视化分析,超越了模型性能汇总统计,以此来提高准确性;
将可视化分析系统和标准模型训练计算分开的能力,帮助更快和更灵活进行模型开发。
目前,Manifold 是一个独立的 Web 工具和 Python 包。为了增加 Manifold 的功能,我们计划把 Manifold 工具集成到 Uber 众多的数据科学平台上,进一步将该工具作为数据科学工作流的关键部分。通过这样做,我们将能够真正发挥 Manifold 数据无关性的潜力,以此来解决公司的各种数据科学使用场景问题。自此,我们打算根据这些应用程序进行设计改进,从而为这些用例提供更强大的支持。
英文原文:https://eng.uber.com/manifold/