作为一家在人工智能领域大量投资的公司,Uber的目标是在产品开发和日常业务管理中利用机器学习(ML)。为了实现这一目标,我们的数据科学家花费了大量的时间对强大的新型ML模型进行原型设计和验证,以解决Uber最具挑战性的问题(例如,基于NLP的智能回复系统,票辅助系统,欺诈检测,金融而且市场预测).一旦一种模型类型经过经验验证是最适合该任务的,工程师就会与数据科学团队密切合作,将其生产出来,并使其在uber规模上提供低延迟服务。这种原型、验证和生产的循环是Uber ML创新的核心,在这个过程的每个阶段摩擦越少,Uber创新的速度就越快。
我们仔细观察了这个创新周期,得出以下结论:
- 不出所料,绝大多数数据科学家更喜欢用Python工作,部分原因是丰富的科学库生态系统,部分原因是如今几乎所有重要的深度学习和ML研究都是用Python发表的。雷竞技是骗人的
- 因为像Hive和Apache Spark这样的大数据工具可能需要几天的设置和数小时的执行,大多数数据科学家更喜欢预先收集数据,并在本地迭代他们的原型,使用工具熊猫,scikit-learn,PyTorch,TensorFlow.
- 经验验证模型通常需要在线实验和大规模的离线验证。第一步需要在线服务模型,第二步需要将模型移植到离线数据处理器可以利用的格式(在Uber,我们通常使用原生Apache Spark或PySpark)。这两个步骤都涉及大量的工作,并且确保模型的在线和离线版本是等价的可能是具有挑战性的。
为了满足这些需求,我们开发了Michelangelo PyML,这是一个支持快速Python ML模型开发的平台。作为第一步,我们构建了一个集成米开朗基罗这使得为在线或离线用例大规模服务任意基于python的模型就像请求搭车一样简单。
这些模型可以包含任意的用户代码,并且可以依赖于任何Python包和本机Linux库。在接下来的部分中,我们将详细介绍我们如何构建这个平台,以及它如何允许数据科学家在实时生产实验以及大规模并行的离线预测工作中本地运行模型的相同副本。所有这些功能都可以通过一个简单的Python SDK访问,并且可以直接从数据科学家最喜欢的开发环境(比如Jupyter笔记本)中利用,而不必在不同的应用程序之间切换。我们的解决方案利用了几个开源组件,应该可以移植到其他ML平台和模型服务系统。
PyML在米开朗基罗中的地位
2017年9月,我们介绍了Uber的机器学习平台Michelangelo.米开朗基罗使Uber的产品团队能够在Uber的规模上无缝地构建、部署和运行机器学习解决方案,目前每秒可实现大约100万次预测。
米开朗基罗在建造时考虑到了性能和规模;支持的模型类型(如XGBoost、GLM和各种回归)可以通过Apache Spark在可用的非常大的数据集上进行训练Uber的HDFS数据湖.这些训练过的模型被具体化为Apache Spark管道,可以用于大规模离线预测,也可以用于高qps的在线预测请求。请阅读我们关于米开朗基罗的原创文章有关其架构的详细信息。
然而,米开朗基罗对性能和规模的关注是以灵活性为代价的:
- 用户只能训练算法得到米开朗基罗支持的模型。如果用户需要训练不受支持的算法,他们必须扩展平台的训练、部署和服务组件。
- 特征转换仅限于米开朗基罗DSL的词汇和表现力。如果用户需要不同的转换,他们必须在Hive中预处理数据或扩展米开朗基罗的DSL,这是一种相当有侵入性的操作。
- 为了实现高效的模型服务,Michelangelo模型以及模型的库依赖被加载到内存中并从内存中提供服务。因此,米开朗基罗的训练和服务系统依赖于所有受支持模型类型的所有依赖关系,随着每增加一个模型类型,依赖关系图的整体复杂性也随之增加。
这种明确选择的性能和可伸缩性优于灵活性的权衡,使得我们的数据科学团队难以快速迭代和试验新的ML模型。PyML是作为米开朗基罗的自然扩展而构建的,以缩小灵活性差距,并使该平台成为高效、高qps模型以及最大程度可定制和实验模型的一站式商店。一旦模型被PyML完全验证,并且需要在大规模的在线环境中使用,用户可以在Michelangelo中复制它们,以充分利用平台的资源效率(例如,非常低的服务延迟,计算/内存高效执行),如下面的图1所示:
使用PyML
下面展示了数据科学家如何在Jupyter Notebook中使用PyML来部署在公开可用的文档上训练的逻辑回归模型数据集威斯康星大学[1]。这些特征包括从乳腺癌肿瘤的显微镜图像中测量的各种细胞核,而标签则是专家医学诊断。
火车模型
准备PyML模型容器
与PyML平台一起使用的训练过的模型必须遵守PyML模型契约。该契约基于一种非常简单的约定:用户为PyML模型奉献一个文件系统“主”文件夹,在该文件夹中保存所有模型构件(如模型权重)。除了构件,平台还希望在主文件夹中找到以下用户提供的文件,这些文件通常由git支持:
让我们创建预测模型的主文件夹,并保存模型构件:

现在我们已经保存了模型构件,我们可以实现预测契约并告诉PyML包依赖关系。
让我们提供model.py并实现PyML的预测契约,DataFrameModel:
现在,让我们从主文件夹实例化一个PyML模型,并验证它是否工作:
最后,让我们打包模型,并在幕后创建一个Docker映像(稍后详细介绍):
打包的模型现在在Michelangelo中进行了版本控制和管理,为在线部署和离线预测做好了准备。此外,其他用户现在可以下载模型并轻松地继续迭代。最后,该模型现在也可以在Michelangelo的UI中使用,如下所示,允许用户轻松浏览他们所有的托管PyML模型,点击部署,配置其访问控制列表,等等:
将模型部署到生产端点并进行预测
几秒钟后,模型将在生产主机上可用,由米开朗基罗的服务基础设施自动监控,并准备服务流量:
进行大规模离线预测
在用户生成离线预测之前,评分数据集必须在Hive中。让我们指导PyML如何找到数据集以及预测结果应该写到哪里:
根据用户数据集的大小,结果将在几分钟、几小时或几天后出现在目标表中。注意,我们能够对几秒钟前部署到在线服务系统的相同模型运行脱机批处理预测—不需要更改一行代码!
PyML架构
PyML的体系结构(如下图3所示)为科学家提供了足够的结构,使他们能够快速、可靠地跨环境部署模型,而不限制他们可以使用的数据类型或可以部署的模型类型。实现这种平衡需要我们仔细考虑表示数据、模型和执行环境的抽象。
数据模型
PyML为用户提供了两种开箱即用的数据类型:DataFrames,其中存储表式结构化数据张量,它存储命名的多维数组。虽然PyML数据类型的列表是可扩展的,但我们的经验是,大多数模型分为两个阵营:一个是操作DataFrames的,如scikit-learn模型;另一个是操作命名张量包的,如TensorFlow和PyTorch模型。
其他模型部署框架提供的数据模型结构不那么结构化,也不那么主观,例如JSON输入,JSON输出.还有一些更具限制性的部署方法甚至可能要求用户预先指定详细的模式定义。PyML走的是中间路线,正如我们将要讨论的那样,在数据模型中提供一些结构而又不过分规范,会带来许多生产力和效率方面的好处。
模型定义
如上所示,用户为他们的模型model.py创建一个单一入口点,其中分别包含一个从DataFrameModel或TensorModel抽象类继承的类。在这两种情况下,用户只需要实现两个方法:一个构造函数加载他们的模型参数,一个predict()方法接受并返回DataFrames或tensor。模型接口抽象出模型将部署在何处以及如何部署,以便用户可以将注意力集中在他们最理解的内容上:进入和退出模型的数据。
Python环境和设置
PyML模型可以加载任何数据文件,并导入模型文件夹中找到的任何Python包。任何其他的PIP、conda或debian软件包都可以分别列在requirements.txt和packages.txt中。可以在setup.sh中提供自定义设置命令,例如下载模型所需的大文件或构建软件包。
验证数据
定义模型的一个重要部分是提供将与模型一起存储的示例数据。此验证数据有多种用途:它提供了一个完整性检查,以确保模型在不同环境中的行为相同,并用作模型的隐式模式定义。
在实践中,用户提供示例数据要比编写模式定义容易得多,特别是当模型具有大量变量时。这是PyML保持Python的灵活性和生产力,同时提供生产模型部署所需的问责性和一致性的一种方法。
执行环境
PyML确保用户的模型在多个环境中为相同的输入产生相同的输出:用户的本地机器、Apache Spark集群和生产服务器环境。它通过为模型自动创建自定义Docker映像来实现这一点,在此过程中使用提供的验证数据在映像构建时验证模型的正确性。
PyML Docker映像包含整个模型主文件夹,并安装了所有用户提供的debian和conda依赖项。它进一步包含PyML的入口点和服务所需的系统依赖关系(例如PySpark和gRPC)。一旦模型图像成功构建并通过验证,就可以使用相同的图像进行离线和在线预测。
离线预测
有些模型被设计为作为每日或每小时批处理作业部署,而其他模型被部署为在线服务。在任何一种情况下,在部署之前能够在大量数据上评估模型通常是有用的。
为每个模型开发一个定制的PySpark作业是非常繁琐的,而且可能会导致离线和在线模型实现之间的偏差,特别是当一个模型有很多Python或系统依赖时。PyML不仅通过完全自动化这个过程来节省用户的时间,还可以防止模型的离线和在线版本之间的细微差异。
要为DataFrame模型生成脱机预测,PyML用户只需提供一个SQL查询,其中的列名和类型与模型所期望的输入相匹配,以及存储输出预测的目标Hive表的名称。在幕后,PyML使用与在线服务模型相同的图像和Python环境启动一个容器化PySpark作业,以确保离线和在线预测之间没有差异。
在线预测
现有服务基础设施
历史上,用户只能部署通过米开朗基罗的Apache Spark培训管道生产的模型。部署请求通知一个适当的Docker容器集群(驻留Michelangelo的在线预测服务)从blob存储中下载模型并将其加载到内存中。当一个模型被加载和验证后,它就可以通过在线预测服务的Thrift/RPC接口接受预测请求了,如下面的图4所示:
对于PyML模型,我们希望尽可能多地利用Michelangelo现有的部署、在线服务和监视基础设施。这要求我们想出一种方法,让基于java的在线预测服务与基于python的模型通信,而不会产生显著的延迟开销。
PyML服务扩展
我们提出的解决方案允许我们将PyML模型作为嵌套的Docker容器共同托管在托管在线预测服务的Docker容器中,如下图5所示:
除了用户提供的模型依赖项和构件外,PyML Docker映像还包含一个轻量级RPC服务器,以允许在线预测服务将预测请求路由到PyML模型。在接收到部署请求后,在线预测服务通过Mesos的API启动PyML特定模型的Docker映像作为嵌套的Docker容器。当容器启动时,它启动PyML RPC服务器,并开始监听来自在线预测服务的Unix域套接字上的预测请求。
通过添加对基于docker的模型和基于Apache spark的内存模型的支持,我们能够重用米开朗基罗经过实战考验的部署和服务基础设施。
前进
PyML在我们那些希望对深度学习模型进行回测和产品化的数据科学家中很受欢迎。PyML的用例示例包括驱动程序提升模型、利用计算机视觉模型的自动化文档处理工具以及各种NLP应用程序。未来,我们将继续在PyML平台上投入大量资金,以进一步加快Python机器学习迭代周期。马上要实现的是PyML功能的扩展,以获得更大的可再现性和与超级的实验平台和米开朗基罗的特色商店。
再现性
作为PyML模型生产部署过程的一部分,我们对模型构件进行版本化和管理。然而,PyML目前并没有首先对导致模型工件的工件和管道进行版本化。这包括用于训练模型的数据、应用的转换,当然还有训练脚本。
将来,我们将为用户提供PyML模型的训练代码及其源数据以及模型构件的版本选择,允许公司的用户从头重新生成PyML模型。
与Uber的实验平台整合
在任何时候,Uber都在通过我们的实验平台.有了PyML,数据科学家现在可以快速迭代和部署他们的模型。为了进一步收紧反馈循环,我们计划与我们的XP紧密集成。这将允许我们的用户将PyML模型直接部署到自动创建的实验中。
与米开朗基罗特色商店整合
在正确的时间内将正确的数据送到正确的位置仍然是机器学习中最困难的问题。作为之前描述的,米开朗基罗的特征库帮助解决了这个问题,它使数据科学家能够有效地启动新的ML项目,或使用来自数万个特征的高度精选集的数据改进现有的ML项目。
到目前为止,我们的用户只有通过米开朗基罗的训练管道训练他们的模型才能利用这些功能。有了PyML,特性库的价值将为所有用户解锁:使用PyML的数据科学家将能够通过利用公司各个团队成功使用的特性来加快他们的模型开发。这将允许他们专注于最重要的任务:训练和评估新模型,而不必担心数据管道和在预测时为模型获取正确的数据。
如果您对使用PyML、Michelangelo和整个Uber机器学习堆栈感兴趣,请点击查看这些职业机会!
引用
[1] Wolberg, Street和Mangasarian(1995)。UCI机器学习库[http://archive.ics.uci.edu/ml]。加州尔湾:加州大学信息与计算机科学学院。
订阅我们的通讯以跟上优步工程的最新创新。
Kevin Stumpf是优步机器学习平台团队的技术主管经理,Stepan Bedratiuk是高级软件工程师。Olcay Cirit是Uber AI实验室的高级软件工程师。我们感谢洛根·杰亚、约瑟夫·王、杰克·拉金和杰里米·赫尔曼,他们帮助这个项目成为可能。我们也非常感谢Stephanie Blotner、Molly Vorwerck和Wayne Cunningham在审阅这篇文章时的帮助。











