原文作者:Jason Sleight,ML(Machine Learning)平台集团技术负责人
翻译:数字化营销工兵
了解数据是Yelp成功的重要组成部分。为了将我们的消费者与当地优秀的企业联系起来,我们每天为各种任务提供数百万条建议,如:
- 立即为你找到水管工来修理漏水的水槽的报价
- 帮助您发现哪些餐厅现在开放送餐
- 确定最受欢迎的菜肴供您在这些餐厅尝试
- 推断可能提供的服务,使企业主能够在Yelp上自信准确地代表他们的业务
大约在2004年Yelp的早期,工程师们煞费苦心地设计了启发式规则来支持这样的建议,但随着产品的成熟和消费者群的增长,他们转向了机器学习(ML)技术。如今,有数百个ML模型以各种形式为Yelp提供支持,ML的采用也在不断加快。
随着我们对ML的采用不断增加,我们的ML基础设施也随之增长。今天,我们宣布推出我们的ML平台,这是一个强大的、全功能的系统集合,用于训练和服务基于开源软件的ML模型。在这篇最初的博客文章中,我们将专注于动机和高级设计。我们有一系列的博客文章,可以更深入地讨论每个组件的技术细节,所以请定期查看!
Yelp的ML之旅
Yelp的第一个ML模型集中在几个团队中,每个团队都创建了自定义的培训和服务基础设施。这些系统是为应对各自领域的挑战而量身定制的,思想的异花授粉并不常见。拥有ML模型在建模和基础设施维护方面都是一项巨大的投资。
经过几年的时间,每个系统都由其团队的工程师逐步扩展,以解决日益复杂的范围和更严格的服务级别目标(SLO)。维护这些系统的操作负担造成了沉重的损失,并将ML工程师的注意力从建模迭代或产品应用程序上转移开。
几年前,Yelp创建了一个Core ML团队,在集中支持的工具和最佳实践下整合我们的ML基础设施。好处是:
1. ML工作流的集中管理系统将使ML开发人员能够专注于项目的产品和ML方面,而不会陷入基础设施的困境。
2. 通过为我们的核心ML团队配备基础设施工程师,我们可以提供ML工程师可能缺乏专业知识来创建或维护的新的前沿功能。
通过整合系统,我们可以提高系统效率,提供一个更强大的平台,具有更紧密的SLO和更低的成本。
3. 为ML这样广泛的主题整合系统是令人生畏的,因此我们首先将ML系统分解为三个主要主题,并在每个主题中开发解决方案:交互式计算、数据ETL和模型训练/服务。该方法运行良好,允许团队将部分工作流程迁移到Core ML工具上,同时根据需要将其领域的其他专门方面留在遗留系统上。
在这篇博客文章中,我将讨论如何将我们的模型训练和服务系统构建成一个单一的、统一的模型平台。
Yelp的ML平台目标
从高层来看,我们的ML平台有几个主要目标:
- Opinionated API,具有针对常见情况的预构建实现。
- 默认情况下的正确性和稳健性。
- 利用开源软件。
Opinionated API
Yelp的许多ML挑战都属于一组有限的常见案例,因此我们希望我们的ML平台能够实施Yelp的集体最佳实践。元数据日志记录、模型版本控制、再现性等考虑因素很容易被忽视,但对于长期的模型维护来说却是非常宝贵的。我们不希望开发人员费力地研究所有这些细节,而是希望我们的ML平台在默认情况下抽象并应用最佳实践。
除了规范我们的ML工作流,固执己见的API还使我们能够简化模型部署系统。通过将开发人员集中到更窄的方法中,我们可以支持自动化的模型服务系统,该系统允许开发人员通过在web UI上点击几次来生产他们的模型。
默认情况下的正确性和稳健性
Yelp历史ML工作流程中最常见的痛点之一是系统验证。理想情况下,应该使用用于训练模型的相同精确代码来对模型进行预测。不幸的是,这往往说起来容易做起来难——尤其是在Yelp这样一个多样化、大规模、分布式的生产环境中。我们通常用Python来训练我们的模型,但可能会通过Java、Scala、Python、内部数据库等来部署模型。
即使是最微小的不一致也会对生产模型产生巨大的差异。例如,我们遇到一个问题,XGBoost升压器无意中使用了64位浮点进行预测(XGBoost仅使用32位浮点)。当对一个重要的分类变量进行数字编码时,轻微的浮点差异导致该模型对35%的实例给出近似随机的预测!
容忍稀疏向量表示、缺失值、null和NaN也需要特别考虑。尤其是当不同的库和语言对客户端预处理这些问题有不同的期望时。例如,一些库将零视为缺失,而另一些库则有特殊名称。对于开发人员来说,仔细考虑这些实现细节是极其复杂的,更不用说识别是否发生了错误了。
在设计ML平台时,我们采用了测试驱动的开发思想。我们所有的代码都有一套完整的端到端集成测试,我们通过测试运行实际的Yelp生产模型和数据集,以确保模型在我们的整个生态系统中给出完全相同的结果。除了确保正确性,这还确保了我们的ML平台足够强大,可以处理混乱的生产数据。
利用开源解决方案
ML目前正在经历开源技术的复兴。Scikit-learn、XGBboost、Tensorflow和Spark等库已经存在多年,并继续提供基本的ML功能。但像Kubeflow、MLeap、MLflow、TensorFlow Extended等新添加的内容重新定义了ML系统应该包含的内容,并为ML系统提供了急需的软件工程最佳实践。
对于Yelp的ML平台,我们认识到,我们可能构建的任何内部解决方案都会很快被这些开源项目不断增长的能力所超越。相反,我们选择了最符合我们需求的开源库,并围绕它们构建了薄包装器,以便更容易地与我们的遗留代码集成。在开源工具缺乏所需功能的情况下,我们会向上游提供解决方案。
ML平台技术概述
在未来的博客文章中,我们将更详细地讨论这些系统,所以请尽快回来查看。现在,我只简单概述一下这些系统中的关键技术选择和模型的生命周期。
MLflow和MLeap
在评估了各种选项后,我们决定将MLflow和MLeap作为我们平台的骨架。
MLflow的目标是简化ML生命周期的管理,并包含各种子组件,每个子组件都针对ML工作流的不同方面。对于我们的ML平台,我们特别关注MLflow跟踪功能。我们自动将参数和指标记录到跟踪服务器上,然后开发人员使用MLflow的web UI来检查模型的性能,比较不同的模型版本等。
MLeap是一种序列化格式和执行引擎,为我们的ML平台提供了两个优势。首先,MLeap开箱即用,支持Yelp最常用的ML库:Spark、XGBoost、Scikit-learn和Tensorflow,此外还可以扩展到自定义转换器,以支持边缘案例。其次,MLeap是完全可移植的,可以在任何基于JVM的系统中运行,包括Spark、Flink、ElasticSearch或微服务。总之,MLeap为我们的模型提供了一个单一的解决方案,满足健壮性/正确性保证和按钮部署等需求。
我司ML平台中的典型代码流
(离线代码流 - 用于机器学习平台里训练一个模型的离线代码流)
开发人员首先构建一个训练数据集,然后定义一个用于编码和建模数据的管道。由于Yelp模型通常使用大型数据集,Spark是我们首选的计算引擎。开发人员指定了一个Spark ML Pipeline来进行数据的预处理、编码、建模和后处理。然后,开发人员使用我们提供的API来适应和序列化他们的管道。在后台,这些函数自动与适当的MLflow和MLeap API交互,以记录和绑定管道及其元数据。
(在我们的ML平台中为模型服务的在线代码流)
为了服务于模型,我们围绕MLeap构建了一个瘦包装器,负责从MLflow中获取捆绑包,将捆绑包加载到MLeap中,并将请求映射到MLeap的API中。我们为这个包装器创建了几个部署选项,允许开发人员将他们的模型作为REST微服务、Flink流处理应用程序执行,或者直接托管在Elasticsearch内部进行排名应用程序。在每个部署选项中,开发人员只需为他们想要托管的模型配置MLflow id,然后就可以开始发送请求了!
下一步是什么?
我们一直在逐步推出我们的ML平台,并观察到我们的ML从业者的热情采用。ML平台功能齐全,但我们在路线图上有一些改进。
首先是扩展一组预制模型和变压器。MLflow和MLeap都是通用的,允许完全定制,但这样做有时是一个复杂的过程。我们不需要开发人员学习MLflow和MLeap的内部,而是计划扩展我们的预构建实现,以涵盖更多Yelp的专业用例。
我们还想将我们的模型服务系统与Yelp的A/B实验工具集成。现在可以在单个服务器上托管多个模型版本,但目前依赖于客户端来指定他们希望在每个请求中使用的版本。然而,我们可以进一步抽象这一细节,并使服务基础设施直接连接到实验共同启动逻辑。
在此基础上,我们希望通过Yelp的实时流媒体基础设施将实际观察到的事件反馈到系统中。通过将观察到的事件与预测的事件相结合,我们可以实时监控ML性能(针对不同的实验队列)。这实现了一些令人兴奋的特性,如模型退化的自动警报、通过强化学习技术进行的实时模型选择等。