DataBrick-数据科学实践指南-全-
DataBrick 数据科学实践指南(全)
原文:
annas-archive.org/md5/b8c4a9294a6f85debae53a7b0abdca7d
译者:飞龙
前言
本书专为经验丰富的数据科学家和开发人员设计,是您利用 Databricks 进行端到端机器学习项目的权威指南。假设读者具备扎实的 Python、统计学、机器学习生命周期基础,并对 Spark 有初步了解,本书旨在帮助专业人士从 DIY 环境或其他云平台过渡到 Databricks 生态系统。
从简洁的机器学习领域概述开始,接着深入探讨 Databricks 的功能和 MLflow 框架。涵盖数据准备、模型选择和训练等关键要素,同时利用 Databricks 特征存储进行高效的特征工程。使用 Databricks AutoML 快速启动项目,并学习如何通过 Databricks 工作流自动化模型再训练和部署。
本书结束时,您将熟练掌握使用 MLflow 进行实验追踪、团队协作,并解决诸如模型可解释性和治理等高级需求。本书包含大量实用的代码示例,重点介绍当前的普遍可用功能,同时帮助您快速适应机器学习、Databricks 和 MLflow 中的新兴技术。
本书适合谁阅读?
本书为精通 Python、统计学和机器学习生命周期的数据科学家和开发人员编写,是您过渡到 Databricks 的指南。特别适合那些从 DIY 或其他云平台迁移的读者,假设读者具备 Spark 入门知识,涵盖从头到尾的机器学习工作流。
本书内容涵盖
第一章**,机器学习过程及其挑战,概述了各个领域中不同的数据科学用例。它概述了机器学习项目中涉及的不同阶段和角色,从数据工程到分析、特征工程、以及机器学习模型的训练和部署。
第二章**,Databricks 上的机器学习概述,指导您完成注册 Databricks 试用帐户的过程,并探索专为机器学习从业者工作空间设计的机器学习功能。
第三章**,利用特征存储,为您介绍特征存储的概念。我们将引导您通过使用 Databricks 的离线特征存储来创建特征表,并演示它们的有效使用。此外,我们还将讨论在机器学习工作流中使用特征存储的优势。
第四章**,理解 Databricks 上的 MLflow 组件,帮助您了解 MLflow 是什么、其组件及其使用的好处。我们还将讲解如何在 MLflow 模型注册中心注册模型。
第五章**, 使用 Databricks AutoML 创建基准模型,介绍了什么是 AutoML,它的重要性,以及 Databricks 在 AutoML 方面的做法。我们还将使用 AutoML 创建一个基准模型。
第六章**, 模型版本控制和 Webhooks,教你如何利用 MLflow 模型注册表来管理模型版本、从不同阶段过渡到生产环境,并使用 webhooks 设置警报和监控。
第七章**, 模型部署方法,介绍了利用 Databricks 平台部署 ML 模型的不同选项。
第八章**, 使用 Databricks Jobs 自动化 ML 工作流,解释了 Databricks 作业是什么,以及如何将其作为强大的工具来自动化机器学习工作流。我们将介绍如何使用 Jobs API 设置 ML 训练工作流。
第九章**, 模型漂移检测和再训练,教你如何检测和防止生产环境中的模型漂移。
第十章**, 使用 CI/CD 自动化模型再训练和重新部署,演示了如何将 Databricks 的 ML 开发和部署设置为 CI/CD 管道。我们将使用书中之前学习的所有概念。
为了最大限度地利用本书
在深入探讨本书提供的动手实践和代码示例之前,了解软件和知识的前提条件非常重要。以下是概述你所需要的内容的总结表:
前提条件 | 描述 |
---|---|
Databricks Runtime | 本书针对 Databricks Runtime 13.3 LTS 及以上版本进行编写。 |
Python 熟练度(3.x) | 你应当熟练掌握至少 Python 3.x,因为代码示例主要是用这个版本编写的。 |
统计学和 ML 基础 | 假设你对统计学和机器学习生命周期有深入的理解。 |
Spark 知识(3.0 或以上) | 需要具备对 Apache Spark 3.0 或以上版本的基础了解,因为 Databricks 是基于 Spark 构建的。 |
Delta Lake 功能(可选) | 对 Delta Lake 功能的基础知识理解可以增强你的理解,但并非强制要求。 |
为了充分利用本书中描述的所有功能和代码示例,你需要一个 Databricks 试用账户,试用期为 14 天。我们建议你计划好学习进度,在此期间完成动手活动。如果你发现这个平台有价值,并希望在试用期后继续使用,考虑联系你的 Databricks 联系人设置付费工作区。
如果你使用的是本书的数字版本,我们建议你自己输入代码,或者从本书的 GitHub 仓库获取代码(下一个章节中有链接)。这样可以帮助你避免因复制粘贴代码而可能出现的错误。
完成本书后,我们强烈建议你浏览 Databricks 文档中的最新功能,无论是私有预览还是公共预览。这将为你提供机器学习在 Databricks 上发展的未来方向,帮助你走在前沿,充分利用新兴功能。
下载示例代码文件
你可以从 GitHub 下载本书的示例代码文件,链接地址为 github.com/PacktPublishing/Practical-Machine-Learning-on-Databricks
。如果代码有更新,它将在 GitHub 仓库中进行更新。
我们还提供了其他代码包,来自我们丰富的书籍和视频目录,链接地址为 github.com/PacktPublishing/
。快来看看吧!
使用的约定
本书中使用了许多文本约定。
文本中的代码
:表示文本中的代码字、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 账号。例如:“在第五个单元格中,我们首先初始化一些参数,如现有用户名 experiment_name
,这是与我们的 AutoML 关联的实验名称,以及 registry_model_name
,这是模型在模型注册表中的名称。”
代码块设置如下:
iris = load_iris() X = iris.data # Features
y = iris.target # Labels
任何命令行输入或输出如下所示:
from sklearn.datasets import load_iris # Importing the Iris datasetfrom sklearn.model_selection import train_test_split # Importing train_test_split function
from sklearn.linear_model import LogisticRegression # Importing Logistic Regression model
粗体:表示一个新术语、一个重要单词或屏幕上显示的单词。例如,菜单或对话框中的单词会显示为 粗体。例如:“要查看你的运行时包含哪些库,可以参考 Databricks 运行时发布说明中的 系统环境 小节,检查你特定的运行时版本。”
提示或重要说明
如下所示。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果你对本书的任何部分有疑问,可以通过电子邮件联系 [email protected],并在邮件主题中注明书名。
勘误表:虽然我们已尽力确保内容的准确性,但错误仍然可能发生。如果你在本书中发现了错误,我们将非常感激你向我们报告。请访问 www.packtpub.com/support/errata 并填写表单。
盗版:如果你在互联网上遇到我们作品的任何非法复制品,我们将感激你提供相关网址或网站名称。请通过 [email protected] 联系我们,并附上该材料的链接。
如果你有兴趣成为作者:如果你对某个话题有专业知识,并且有兴趣撰写或参与编写一本书,请访问 authors.packtpub.com。
评论
请留下评论。一旦你阅读并使用了本书,为什么不在你购买它的网站上留下评论呢?潜在的读者可以通过你的公正意见做出购买决策,我们在 Packt 可以了解你对我们产品的看法,而我们的作者也能看到你对他们书籍的反馈。谢谢!
关于 Packt 的更多信息,请访问 packtpub.com。
分享你的想法
一旦你阅读了 Practical Machine Learning on Databricks,我们很想听听你的想法!请 点击这里直接进入亚马逊评论页面 并分享你的反馈。
你的评论对我们和技术社区非常重要,将帮助我们确保提供卓越的内容质量。
下载本书的免费 PDF 版本
感谢购买本书!
你喜欢随时随地阅读,但又无法将印刷版书籍带到处吗?你的电子书购买无法与所选设备兼容吗?
不用担心,现在每本 Packt 书籍都会免费附带 DRM 无保护的 PDF 版本。
在任何地方、任何设备上阅读。直接从你最喜欢的技术书籍中搜索、复制和粘贴代码到你的应用程序中。
特权不止于此,你还可以获得独家折扣、新闻通讯和每天送到你邮箱的精彩免费内容
按照以下简单步骤来享受优惠:
- 扫描二维码或访问以下链接
packt.link/free-ebook/9781801812030
-
提交你的购买证明
-
就是这样!我们会直接将你的免费 PDF 和其他福利发送到你的邮箱
第一部分:简介
本部分主要关注数据科学用例、数据科学项目的生命周期以及涉及的角色(数据工程师、分析师和科学家),以及组织中机器学习开发的挑战。
本节包含以下章节:
-
第一章,机器学习过程及其挑战
-
第二章,Databricks 上的机器学习概述
第一章:机器学习过程及其挑战
欢迎来到使用 Databricks 平台简化你的机器学习(ML)生命周期的世界。
作为 Databricks 的高级解决方案架构师,专注于机器学习,多年来,我有机会与企业合作,架构能够解决其独特商业用例的机器学习平台,使用 Databricks 平台。现在,这段经验将为你提供学习资源。你从本书中获得的知识将为你开启新的职业机会,并改变你为组织的机器学习用例架构机器学习流水线的方式。
本书假定你已经对 Python 语言有一定了解,因为附带的代码示例将使用 Python。 本书并不是从零开始教授机器学习技术;它假设你是一个经验丰富的数据科学从业者,想要学习如何利用 Databricks 平台将你的机器学习用例从开发到生产以及中间的所有步骤。
本书需要一定的 Python 和 pandas 知识。熟悉 Apache Spark 是加分项,具备扎实的机器学习和数据科学基础是必要的。
注意
本书重点介绍当前一般可用的功能。提供的代码示例使用 Databricks 笔记本。尽管 Databricks 正在积极开发支持使用外部集成开发环境(IDEs)的工作流的功能,但本书未涵盖这些特定功能。此外,阅读本书将为你奠定坚实的基础,使你能够在新功能发布时快速掌握它们。
本章将涵盖以下内容:
-
理解典型的机器学习过程
-
发现参与组织中机器学习过程的各个角色
-
在组织中将机器学习用例投入生产的挑战
-
理解企业机器学习平台的需求
-
探索 Databricks 和 Lakehouse 架构
本章结束时,你应该对企业中典型的机器学习开发生命周期以及其中涉及的不同角色有基本的了解。你还将知道为什么大多数机器学习项目未能带来商业价值,并且了解 Databricks Lakehouse 平台如何提供解决方案。
理解典型的机器学习过程
下图总结了组织中的机器学习过程:
图 1.1 – 数据科学开发生命周期包括三个主要阶段——数据准备、建模和部署
注意
这是一种迭代过程。原始的结构化和非结构化数据首先从不同的来源进入数据湖。数据湖利用云存储提供的可扩展且低成本的存储服务,例如Amazon 简单存储服务(S3)或Azure 数据湖存储(ADLS),具体取决于组织使用的云服务商。由于法规要求,许多组织采用多云策略,这使得选择云中立的技术和框架变得至关重要,从而简化基础设施管理并降低运营成本。
Databricks 定义了一种名为勋章架构的数据湖组织设计模式。在继续之前,我们先简要了解一下什么是勋章架构:
图 1.2 – Databricks 勋章架构
勋章架构是一种数据设计模式,用于在湖仓中逻辑地组织数据。它通过将数据结构化为多个层次(铜层、银层和金层)来逐步改善数据的质量和结构。勋章架构也被称为“多跳”架构。
湖仓架构结合了数据湖和数据仓库的最佳特性,提供了多个优点,包括简单的数据模型、易于实现、增量的提取、转换和加载(ETL)以及能够随时从原始数据重新创建表格的能力。它还提供了诸如 ACID 事务和数据版本控制与历史分析的时间旅行等功能。我们将在探索 Databricks 湖仓 架构 部分进一步展开湖仓的内容。
在勋章架构中,铜层保存从外部系统获取的原始数据,保留其原始结构以及附加的元数据。这里的重点是快速的变更数据捕获(CDC)和维护历史档案。银层则存放经过清洗、符合标准的以及“恰好足够”转换后的数据。它提供了一个企业范围内的关键业务实体视图,并作为自助分析、临时报告和高级分析的来源。
黄金层是精心策划的业务级表所在的位置,这些表已经为消费和报告目的进行了组织。该层使用去规范化、读优化的数据模型,减少了连接操作。这里应用了复杂的转换和数据质量规则,为各种项目提供了最终的展示层,如客户分析、产品质量分析、库存分析等。传统的数据集市和企业数据仓库(EDWs)也可以集成到湖仓中,以支持全面的“全企业数据仓库”高级分析和机器学习。
宝石架构与数据网格的概念非常契合,其中铜层和银层表可以以“一对多”的方式进行连接,生成多个下游表,从而提升数据的可扩展性和自主性。
在过去六年里,Apache Spark 因性能提升和大规模开发者社区的采纳与支持,已经取代了 Hadoop,成为处理大规模数据的事实上的标准。关于 Apache Spark,有许多由 Apache Spark 的创造者亲自撰写的优秀书籍;这些书籍已经列在了进一步阅读部分。它们能为你提供更多关于 Apache Spark 其他好处的见解。
一旦清洗后的数据进入金标准表,特征便通过结合黄金数据集生成,这些数据集作为机器学习模型训练的输入。
在模型开发和训练阶段,会测试不同的超参数和机器学习算法,以确定模型及其相应超参数的最佳组合。这个过程依赖于预先确定的评估指标,如准确率、R2 分数和 F1 分数。
在机器学习的背景下,超参数是控制模型学习过程的参数。它们不是从数据中学习到的,而是在训练之前设置的。超参数的例子包括学习率、正则化强度、神经网络中的隐藏层数,或支持向量机中核函数的选择。调整这些超参数会显著影响模型的表现和行为。
另一方面,训练一个机器学习模型涉及推导其他模型参数的值,如节点权重或模型系数。这些参数是在训练过程中使用训练数据学习的,通过最小化选择的损失或误差函数来优化。它们特定于所训练的模型,并通过梯度下降或闭式解等优化技术迭代确定。
超越节点权重,模型参数还可以包括回归模型中的系数、截距项、决策树中的特征重要性评分,或卷积神经网络中的滤波器权重。这些参数在训练过程中直接从数据中学习,并有助于模型进行预测。
参数
你可以在en.wikipedia.org/wiki/Parameter
了解更多关于参数的信息。
完成的模型将作为表现状态转移(REST)端点,通过容器进行批处理、流处理或实时推理部署。在此阶段,我们会设置监控机制以检测漂移并对已部署的模型进行治理,以便管理模型生命周期并强制执行使用控制。让我们看一下在将机器学习用例从开发阶段推向生产的过程中,涉及的不同角色。
发现组织中与机器学习项目相关的角色
通常,开发机器学习解决方案的过程中,涉及三种不同类型的角色:
-
数据工程师:数据工程师创建数据管道,将来自源系统的结构化、半结构化和非结构化数据导入数据湖。一旦原始数据进入数据湖,数据工程师还负责安全地存储数据,确保数据可靠、干净,并且易于组织中用户发现和使用。
-
数据科学家:数据科学家与主题专家(SME)合作,理解和解决业务问题,确保项目有充分的业务理由。他们利用来自数据湖的清洗数据,进行特征工程,选择并转换相关特征。通过使用不同超参数集开发和训练多个机器学习模型,数据科学家可以在测试集上评估这些模型,以识别最佳表现的模型。在整个过程中,与主题专家的合作帮助验证模型是否符合业务需求,确保其与目标和关键绩效指标(KPI)的一致性。这种迭代的方法帮助数据科学家选择一个有效解决问题并满足指定 KPI 的模型。
-
机器学习工程师:机器学习工程团队将数据科学家创建的机器学习模型部署到生产环境中。关键是尽早建立程序、治理和访问控制,包括定义数据科学家对特定环境和数据的访问权限。机器学习工程师还会实施监控系统来跟踪模型性能和数据漂移。他们执行治理实践,跟踪模型血统,并确保在整个机器学习生命周期中实施数据安全性和合规性访问控制。
一个典型的机器学习项目生命周期包括数据工程、数据科学,然后是机器学习工程团队的生产部署。这是一个迭代过程。
现在,让我们来看一下在将机器学习模型投入生产过程中所面临的各种挑战。
组织在将机器学习用例投入生产过程中面临的挑战
此时,我们已经了解了组织中典型的机器学习(ML)项目生命周期及参与其中的不同角色。虽然看起来很直观,但我们仍然看到许多企业在从数据科学项目中交付商业价值时遇到困难。
2017 年,Gartner 分析师 Nick Heudecker 承认,85%的数据科学项目失败。Dimensional Research(dimensionalresearch.com/
)发布的一份报告也揭示,仅有 4%的公司成功将机器学习(ML)应用案例投入生产。Rackspace Global Technologies 在 2021 年进行的一项研究显示,来自各行各业的 1,870 家组织中,只有 20%的组织在人工智能(AI)和机器学习(ML)方面有成熟的实践。
来源
有关这些统计数据的更多细节,请参见进一步阅读部分。
大多数企业在成功交付数据科学项目的商业价值时面临一些共同的技术挑战:
-
无意的数据孤岛和杂乱的数据:数据孤岛可以被看作是组织中由特定用户或小组管理和访问的数据集合。存在数据孤岛的一些合理原因包括遵守特定的隐私法相关规定,如欧洲的通用数据保护条例(GDPR)或加利福尼亚隐私权法案(CCPA)等。这些情况通常是例外而非常规。Gartner 曾表示,几乎 87%的组织在分析和商业智能的成熟度上较低,这意味着数据并未得到充分利用。
数据孤岛通常出现在组织内部的不同部门,它们有不同的技术栈来管理和处理数据。
下图突出了这一挑战:
图 1.3 – 组织中不同团队使用的工具和不同的数据孤岛
不同的角色使用不同的工具集,并且有不同的工作环境。数据分析师、数据工程师、数据科学家和 ML 工程师由于各自的角色和目标,使用不同的工具和开发环境。数据分析师依赖 SQL、电子表格和可视化工具来获取洞察和报告。数据工程师使用编程语言和平台,如 Apache Spark,来构建和管理数据基础设施。数据科学家使用统计编程语言、ML 框架和数据可视化库来开发预测模型。ML 工程师将 ML 专业知识与软件工程技能相结合,将模型部署到生产系统中。这些不同的工具集可能在数据一致性、工具兼容性和协作方面带来挑战。标准化的流程和知识共享可以帮助减轻这些挑战,促进有效的团队合作。传统上,这些团队之间几乎没有合作。因此,一个具有验证商业价值的数据科学用例可能无法以所需的速度开发,从而对业务的增长和有效管理产生负面影响。
当过去十年提出数据湖的概念时,它们承诺提供一种可扩展且廉价的解决方案,支持结构化和非结构化数据。目标是使数据能够在整个组织中有效使用和协作。然而,实际上,大多数数据湖最终变成了数据沼泽,几乎没有关于数据质量的治理。
这本质上使得 ML 变得非常困难,因为一个 ML 模型的质量仅仅取决于它所训练的数据。
- 构建和管理一个有效的 ML 生产环境是具有挑战性的:Google 的 ML 团队在设置 ML 开发环境时,围绕技术挑战进行了大量研究。Google 在 NeurIPS 上发布的一篇关于 ML 系统工程中隐性技术债务的研究论文(
proceedings.neurips.cc/paper/2015/file/86df7dcfd896fcaf2674f757a2463eba-Paper.pdf
)记录了编写 ML 代码只是整个 ML 开发生命周期中的一小部分。为了在一个组织中发展有效的 ML 开发实践,需要将多个工具、配置和监控方面整合到整体架构中。一个关键的组成部分是监控模型性能的漂移并提供反馈和再训练:
图 1.4 – 机器学习系统中的隐性技术债务,NeurIPS 2015
让我们更深入地理解企业级 ML 平台的需求。
理解企业级机器学习平台的需求
在快速发展的人工智能(AI)和机器学习(ML)领域,企业级机器学习平台作为关键组成部分,处于核心地位。它是一个综合软件平台,提供构建、部署和管理大规模机器学习模型所需的基础设施、工具和流程。然而,一个真正强大的机器学习平台超越了这些能力,涵盖了机器学习生命周期的每个阶段,从数据准备、模型训练和部署到持续监控和改进。
当我们谈论企业级机器学习(ML)平台时,有几个关键特性决定了其有效性,这些特性每一个都是此类平台的基石。让我们深入探讨这些关键需求,并理解它们在企业环境中的重要性。
可扩展性 – 增长催化剂
可扩展性是一个至关重要的特性,使平台能够适应快速发展的组织需求。在机器学习的背景下,这包括处理海量数据集的能力,管理多个模型的能力,以及容纳越来越多并发用户的能力。随着组织数据量的指数级增长,平台必须具备扩展能力,并高效处理不断增加的数据,同时不降低性能。
性能 – 确保效率和速度
在现实世界的企业环境中,机器学习平台的性能直接影响业务运营。它应当具备在训练和推理阶段提供高性能的能力。这些阶段对确保模型能够用最少的资源高效训练,并且在生产环境中部署,做好及时且准确的预测至关重要。一个高性能的平台意味着更快的决策,而在当今快节奏的商业世界中,每一秒都至关重要。
安全性 – 保护数据和模型
在数据泄露时有发生的时代,机器学习平台的安全性变得尤为重要。一个强大的机器学习平台应当优先考虑安全性,并遵守行业法规。这涉及多种功能,例如严格的数据加密技术、访问控制机制以防止未经授权的访问,以及审计功能以跟踪系统中的活动,所有这些功能共同作用,确保安全地处理敏感数据和机器学习模型。
治理 – 驾驶机器学习生命周期
治理是一个经常被忽视但至关重要的企业级机器学习平台特性。有效的治理工具可以促进机器学习模型生命周期的管理。它们可以控制版本管理,维护模型的演变追踪,并进行审计以确保符合监管要求和透明度。随着机器学习项目复杂性的增加,治理工具通过管理模型和维护清晰可理解的系统,确保顺利运行。
可重复性 – 确保信任和一致性
可重现性是任何机器学习(ML)模型可信度的基础。ML 平台应确保实验结果的可重现性,从而建立模型的可信度和信任感。这意味着在相同的数据和条件下,模型应该始终如一地生成相同的输出。可重现性直接影响决策过程,确保决策的一致性和可靠性,同时使模型值得信赖。
易用性——平衡复杂性与可用性
最后但同样重要的是,ML 平台的易用性。尽管 ML 过程本身具有内在复杂性,但该平台应当直观且用户友好,适合各种用户使用,从数据科学家到 ML 工程师。这包括流畅的用户界面、完善的 API 文档和以用户为中心的设计,使用户在开发、部署和管理模型时更加轻松。易用的平台降低了入门门槛,提高了采用率,并使用户能够更多地专注于 ML 任务本身,而不是为平台而苦恼。
从本质上讲,企业级 MLOps 平台需要具备模型开发、部署、可扩展性、协作、监控和自动化的能力。Databricks 通过提供一个统一的环境,帮助 ML 从业者开发和训练模型,按需大规模部署,并监控其性能。它支持协作,整合流行的部署技术,并提供自动化和 CI/CD 能力。
现在,让我们深入了解 Databricks 湖仓架构及其统一的人工智能/分析平台,这使其成为一个卓越的企业级 ML 平台。
探索 Databricks 和湖仓架构
Databricks 是一个著名的云原生、企业级数据分析平台,它将数据工程、数据科学和机器学习(ML)整合在一起,帮助组织大规模开发和部署 ML 模型。
云原生指的是一种特定为云环境设计、开发和部署的软件应用程序方法。它涉及使用容器、微服务和编排平台等技术来实现可扩展性、韧性和敏捷性。通过利用云的能力,Databricks 可以动态扩展,恢复故障,并快速适应变化的需求,帮助组织最大化云计算的优势。
Databricks 实现了企业级 ML 平台的六大基石。让我们来更详细地看看。
可扩展性——增长催化剂
Databricks 提供完全托管的 Apache Spark(一个开源的分布式计算系统,以其处理大量数据和分布式计算的能力而闻名)集群。
Apache Spark 由多个组件组成,包括节点和驱动程序。节点指的是 Spark 集群中贡献计算资源的单独机器或服务器。驱动程序负责运行用户的应用程序代码,并协调 Spark 作业的整体执行。它与 集群管理器 通信,以分配资源,并管理 SparkContext,它作为访问 Spark 集群的入口点。RDDs 是核心数据结构,支持并行处理,Spark 使用 有向无环图(DAG)来优化计算。转换和 操作 在 RDD 上执行,而集群管理器处理资源分配。此外,缓存和洗牌操作提升了性能。
Spark 中的 DataFrames API 是一个分布式数据集合,组织为命名的列。与直接操作 Spark 中的 RDD 相比,它提供了更高级的抽象,使得操作和分析结构化数据变得更容易。它支持类似 SQL 的语法,并提供了丰富的数据操作和转换功能。
Spark 提供了多种语言的 API,包括 Scala、Java、Python 和 R,允许用户利用现有技能并选择他们最熟悉的语言。
Apache Spark 在多个节点上处理大规模数据集,使其具有高度可扩展性。它支持流处理和批处理。这意味着你可以使用 Spark 处理实时数据流以及大规模批处理作业。Spark 结构化流处理(Spark Structured Streaming)是 Spark 的一个组件,允许你以可扩展和容错的方式处理实时数据流。它提供了高级抽象,使得使用熟悉的批处理概念编写流处理应用程序变得更加容易。
此外,Databricks 允许集群动态扩展和自动扩展,根据工作负载调整资源,确保高效利用资源,同时满足组织日益增长的需求。
尽管本书没有详细讲解 Apache Spark,但我们整理了一个进一步阅读部分,提供了优秀的推荐书单,帮助你更全面地探索 Apache Spark。
性能 – 确保效率和速度
Databricks Runtime 针对云环境进行了优化,并且在开源 Apache Spark 的基础上进行了增强,显著提升了性能。Databricks Delta 引擎为大数据和 AI 工作流提供了快速查询执行,同时减少了数据准备和迭代模型训练所需的时间和资源。其优化的运行时提高了模型训练和推理的速度,从而提升了操作效率。
安全性 – 保护数据和模型
Databricks 通过多种方式确保高级别安全性。它提供数据静态和传输加密,在用户权限方面使用基于角色的访问控制(RBAC),并与身份提供者集成实现单点登录(SSO)。
Databricks 还有一个名为 Unity Catalog 的功能。Unity Catalog 是 Databricks 工作空间的集中式元数据存储,提供数据治理功能,如访问控制、审计、血统和数据发现。其主要特点包括集中式治理、统一安全模型、自动化血统追踪和简便的数据发现。其优点包括改善治理、降低运营开销和增强数据灵活性。Unity Catalog 是增强 Databricks 数据治理的强大工具。Unity Catalog 是本书中不会详细涵盖的复杂主题。但是,你可以在进一步阅读部分找到更多信息,提供了链接。
Databricks 平台符合多个行业法规,包括 GDPR、CCPA、HIPAA、SOC 2 Type II 和 ISO/IEC 27017. 完整的认证列表,请查看 www.databricks.com/trust/compliance
。
治理 - 引导机器学习生命周期
Databricks 提供 MLflow,这是一个管理机器学习生命周期的开源平台,包括实验、可复现性和部署。它支持模型版本控制和模型注册,跟踪模型在生命周期中的阶段(暂存、生产等)。此外,该平台提供审计日志以跟踪用户活动,帮助满足监管要求并促进透明度。Databricks 还拥有自己托管的特征存储,我们将在后面的章节中详细介绍。
可复现性 - 确保信任和一致性
使用 MLflow,Databricks 确保了 ML 模型的可复现性。MLflow 允许用户记录每次实验运行的参数、指标和工件,提供了完成的操作记录,允许精确复制结果。它还支持将代码打包到可复现的运行中,并与他人共享,进一步确保实验的可重复性。
使用便捷性 - 平衡复杂性和可用性
Databricks 提供了一个协作工作空间,使数据科学家和工程师能够无缝协作。它提供了支持多种语言(Python、R、SQL 和 Scala)的交互式笔记本,允许用户使用他们偏好的语言。该平台直观的界面,加上丰富的文档和强大的 API,使其易于使用,帮助用户更专注于机器学习任务,而不是平台管理的复杂性。除了协作和分析能力外,Databricks 还与各种数据源、存储系统和云平台集成,使其灵活且适应不同的数据生态系统。它支持与流行的数据湖、数据库和云存储服务的无缝集成,使用户能够轻松访问和处理来自多个来源的数据。尽管本书专注于 Databricks 的机器学习和 MLOps 能力,但理解 Databricks Lakehouse 架构以及它如何简化组织中的机器学习项目生命周期管理和扩展,依然非常有意义。
Lakehouse 作为一个术语,是两个词的结合:数据湖 和 数据仓库。数据仓库擅长处理结构化数据和 SQL 查询。它们广泛用于为 商业智能(BI)应用程序提供支持,但在支持机器学习方面有所限制。它们以专有格式存储数据,并且只能通过 SQL 查询访问。
另一方面,数据湖在支持机器学习(ML)应用场景方面表现出色。数据湖允许组织将大量的结构化和非结构化数据存储在一个可扩展的中央存储库中。它们容易扩展并支持开放格式。然而,数据湖在运行商业智能(BI)工作负载时有一个显著的缺点。它们的性能无法与数据仓库相比。缺乏架构治理的执行使得许多组织中的数据湖变成了“沼泽”。
通常,在现代企业架构中,既需要数据仓库,也需要数据湖。这正是 Databricks 定义 Lakehouse 架构的背景。Databricks 提供了一个统一的分析平台,称为 Databricks Lakehouse 平台。Lakehouse 平台提供了一个基于角色的单一平台,满足所有数据处理和洞察获取相关人员的需求。这些角色包括数据工程师、BI 分析师、数据科学家和 MLOps。这个平台能够极大地简化任何组织的数据处理和分析架构。
在撰写本书时,Lakehouse 平台已在所有三大云服务平台上提供:Amazon Web Services(AWS)、Microsoft Azure 和 Google Compute Platform(GCP)。
Lakehouse 可以被认为是一种将数据仓库的性能和数据治理功能相结合,并在数据湖的规模上提供这些功能的技术。从技术实现上看,Lakehouse 使用了一种名为 Delta 的开放协议 (delta.io/
)。
Delta 格式为数据湖中的数据添加了可靠性、性能和治理。Delta 还提供了原子性、一致性、隔离性和持久性(ACID)事务,确保所有数据操作要么完全成功,要么完全失败。除了支持 ACID 事务外,Delta 在后台使用 Parquet 格式。与常规 Parquet 格式不同,Delta 格式会跟踪事务日志,提供增强的功能。它还支持对数据的细粒度访问控制,以及版本控制和回滚到先前版本的能力。Delta 格式表格能与数据轻松扩展,并且在 Apache Spark 支持下,通过先进的索引和缓存技术提升大规模操作的性能。Delta 格式还提供了许多其他优势,您可以在官方网站上了解更多信息。
当我们提到Delta Lake时,我们指的是使用 Delta 格式的数据湖,它为数据湖提供了前述的所有好处。
Databricks Lakehouse 架构是基于 Delta Lake 的基础构建的:
图 1.5 – Databricks Lakehouse 平台
注
来源:感谢 Databricks 提供
接下来,让我们讨论 Databricks Lakehouse 架构如何简化 ML。
简化机器学习开发的 Lakehouse 架构
正如我们在上一节看到的,Databricks Lakehouse 平台提供了一个云原生的企业级解决方案,简化了组织的数据处理需求。它提供了一个单一平台,使得企业内不同团队能够协作,并减少新项目的上市时间。
Lakehouse 平台有许多专门面向数据科学家和 ML 实践者的组件;我们将在本书后续章节中详细讲解这些组件。例如,在撰写本书时,Lakehouse 平台推出了一个下拉按钮,允许用户在基于角色的视图之间切换。在 ML 实践者角色视图中,有快速访问完全集成和管理的特性存储、模型注册表和 MLflow 跟踪服务器的标签:
图 1.6 – Databricks Lakehouse 平台角色选择下拉菜单
接下来,让我们总结一下本章内容。
总结
本章中,我们学习了机器学习(ML),包括 ML 流程、相关角色以及组织在生产化 ML 模型时面临的挑战。然后,我们了解了 Lakehouse 架构以及 Databricks Lakehouse 平台如何简化组织中的 MLOps。这些内容为我们深入理解 Databricks 针对 ML 生命周期的不同专用工具提供了坚实的基础。
若要深入学习各种功能并保持最新的公告,Databricks 文档是理想的资源。你可以通过进一步阅读部分提供的链接访问文档。此外,在文档页面上,你可以轻松切换到不同云平台的文档,探索平台特定的细节和功能。
在下一章中,我们将更深入地探讨 Databricks Lakehouse 平台中的机器学习专用功能。
进一步阅读
要了解本章涉及的更多内容,请参考以下资源:
-
维基百科,超参数(机器学习) (
en.wikipedia.org/wiki/Hyperparameter_(machine_learning)
)。 -
Matt Asay,2017 年,85%的大数据项目失败,TechRepublic,11 月 (
www.techrepublic.com/article/85-of-big-data-projects-fail-but-your-developers-can-help-yours-succeed/
)。 -
Rackspace Technologies,全球新的 Rackspace 技术研究揭示广泛存在的人工智能与机器学习知识差距,2021 年 1 月 (
www.rackspace.com/newsroom/new-global-rackspace-technology-study-uncovers-widespread-artificial-intelligence-and
)。 -
Gartner,Gartner 数据显示 87%的组织在商业智能和分析方面的成熟度较低,2018 年 12 月 (
www.gartner.com/en/newsroom/press-releases/2018-12-06-gartner-data-shows-87-percent-of-organizations-have-low-bi-and-analytics-maturity
)。 -
《学习 Spark:极速数据分析》,作者:Holden Karau、Andy Konwinski、Patrick Wendell 和 Matei Zaharia:这本全面的指南涵盖了 Spark 的基础知识,包括 RDD、DataFrame API、Spark Streaming、MLlib 和 GraphX。通过实际示例和使用案例,它将帮助你熟练掌握使用 Spark 进行数据分析。
-
《Spark:权威指南》,作者:Bill Chambers 和 Matei Zaharia:这本备受赞誉的书籍深入探讨了 Spark 的核心概念和高级功能,涵盖了 Spark 的架构、数据处理技术、机器学习、图处理以及部署相关的注意事项。无论是初学者还是有经验的用户,都能全面理解 Spark。
-
高性能 Spark:Apache Spark 扩展与优化最佳实践,作者:Holden Karau、Rachel Warren 和 Matei Zaharia:本书探讨了优化 Spark 应用程序的策略,以实现最大性能和可扩展性。书中提供了关于调整 Spark 配置、改善数据本地性、利用高级功能以及设计高效数据管道的见解。
-
Spark 实战,作者:Jean-Georges Perrin:本实用指南带你了解整个 Spark 生态系统,涵盖数据摄取、转换、机器学习、实时处理以及与其他技术的集成。通过动手示例和实际用例,帮助你将 Spark 应用到具体项目中。
-
开始使用 Unity 目录 (
docs.databricks.com/data-governance/unity-catalog/get-started.html
) -
Databricks 文档 (
docs.databricks.com/introduction/index.html
)。
第二章:Databricks 上的 ML 概述
本章将为你提供如何在 Databricks 上开始进行 ML 操作的基本理解。ML 工作区对数据科学家非常友好,支持通过提供对流行 ML 库(如 TensorFlow、PyTorch 等)的开箱即用支持,快速进行 ML 开发。
我们将涵盖如何设置 Databricks 试用账户,并了解 Databricks 工作区中为 ML 从业者提供的各种 ML 专用功能。你将学习如何在 Databricks 上启动集群并创建新的笔记本。
在本章中,我们将涵盖以下主要内容:
-
设置 Databricks 试用账户
-
Databricks 上的 ML 工作区简介
-
探索工作区
-
探索集群
-
探索笔记本
-
探索数据
-
探索实验
-
探索特征存储
-
探索模型注册表
-
库
这些主题将涵盖在 Databricks 上执行有效ML 操作(MLOps)所需的基本功能。如果你希望更深入地了解某个特定功能,相关的 Databricks 官方文档链接也会包含在适当的地方。
让我们来看一下如何获取 Databricks 工作区的访问权限。
技术要求
对于本章内容,你需要拥有 Databricks 工作区的访问权限,并且具备集群创建权限。默认情况下,工作区的拥有者具有创建集群的权限。我们将在探索集群部分更详细地讨论集群。你可以在这里阅读更多关于不同集群访问控制选项的内容:docs.databricks.com/security/access-control/cluster-acl.html
。
设置 Databricks 试用账户
在撰写本文时,Databricks 已在所有主要云平台上可用,分别是谷歌云平台(GCP)、微软 Azure 和 亚马逊 Web 服务(AWS)。
Databricks 提供了一种简单的方式,可以在社区版中创建账户,或开始为期 14 天的试用,试用期内将提供工作区中的所有企业功能。
为了充分利用本书中提供的代码示例并探索我们将要介绍的企业功能,我强烈建议你利用 14 天的试用选项。这个试用将为你提供所有必要的功能,确保你在整个学习过程中拥有流畅的体验。
请通过以下链接注册试用账户:www.databricks.com/try-databricks?itm_data=PricingPage-Trial#account
填写完介绍表格后,你将被重定向到一个页面,在该页面你可以选择开始在三个云平台中的任一云上进行试用部署,或创建一个社区版账户:
图 2.1 – 如何获得免费的 Databricks 试用账户
一旦注册成功,您将收到一封电子邮件,描述如何登录 Databricks 工作区。
注意
本章中我们将介绍的大部分功能,在 14 天的试用期内均可使用。
登录工作区后,访问左侧导航栏中的角色选择器标签。我们将把我们的角色切换为机器学习:
图 2.2 – 基于角色的工作区切换器
现在,让我们来看看新的 Databricks ML 工作区功能。
探索工作区
工作区位于 Databricks ML 环境内。每个 Databricks ML 环境的用户都有一个工作区。用户可以独立创建笔记本和开发代码,或通过细粒度的访问控制与其他团队成员协作。您将在工作区或仓库中度过在 Databricks 环境的大部分时间。我们将在 仓库 部分深入了解更多内容:
图 2.3 – 工作区标签
需要注意的是,工作区区域主要用于 Databricks 笔记本。虽然工作区确实支持使用 Git 提供者进行版本控制,但需要强调的是,相较于使用仓库,工作区内的版本控制功能现在被认为不太推荐。
版本控制,在软件开发中,是一种帮助跟踪文件随时间变化的系统。它允许您维护修改的历史记录,支持协作、错误跟踪,并在需要时恢复到先前版本。在 Databricks 中,版本控制专门指的是跟踪笔记本中的变更。
为了加强最佳实践,Databricks 正在逐步摆脱仅依赖工作区内的版本控制功能。相反,它强调使用仓库,这种方法为 Databricks 和非 Databricks 特定文件提供了更好的支持。这一战略转变为在 Databricks 环境中管理代码和文件提供了更加全面和多功能的方式。
通过利用仓库,您不仅可以有效地管理和跟踪笔记本的变更,还可以管理其他文件类型的变更。这包括代码文件、脚本、配置文件等。仓库使用流行的版本控制系统,如 Git,支持无缝协作、分支管理、代码审查工作流以及与外部工具和服务的集成。让我们来看看最近加入工作区的 仓库 功能。
仓库
仓库是 repository 的缩写。这个方便的功能让您可以在 Databricks 环境中对代码进行版本控制。使用仓库,您可以将任意文件存储在 Git 仓库中。写作时,Databricks 支持以下 Git 提供者:
-
GitHub
-
Bitbucket
-
GitLab
-
Azure DevOps
Databricks 仓库提供了一种日志机制,用于跟踪和记录用户与 Git 仓库的各种交互。这些交互包括提交代码更改和提交拉取请求等操作。仓库功能也可以通过 REST 应用程序编程接口(API)使用(docs.databricks.com/dev-tools/api/latest/repos.html
)。
图 2.4 – Repos 选项卡
你可以在 https://docs.databricks.com/repos.html#configure-your-git-integration-with-databricks 了解更多关于如何为你的环境设置仓库的信息。仓库对于在 Databricks 环境中设置 CI/CD 流程至关重要。Repos 功能允许用户对代码进行版本控制,并支持可重复性。
持续集成/持续部署(CI/CD)是一种软件开发方法,涉及自动化集成代码更改、测试它们并将其部署到生产环境的过程。在本书的最后一章,我们将讨论更多关于 Databricks 中的部署范式以及作为 MLOps 一部分的 CI/CD:
图 2.5 – 支持的 Git 提供商
现在,让我们来看看集群,Databricks 环境中执行模型训练的核心计算单元。
探索集群
集群是进行机器学习模型训练时执行繁重计算任务的主要计算单元。与集群相关的虚拟机是在 Databricks 用户的云订阅中配置的;然而,Databricks 用户界面提供了控制集群类型及其设置的界面。
集群是短暂的计算资源。集群上不存储数据:
图 2.6 – 集群选项卡
Pools 功能允许最终用户创建 Databricks 虚拟机池。在云环境中工作的一个好处是你可以按需请求新的计算资源。最终用户按秒计费,并且在集群负载较低时归还计算资源。这很好;然而,从云服务提供商请求虚拟机,启动它并将其添加到集群中仍然需要一些时间。通过使用池,你可以预先配置虚拟机并将其保持在待命状态。如果集群请求新节点并且能够访问池,那么如果池中有所需的虚拟机可用,这些节点将在几秒钟内被添加到集群中,帮助减少集群的扩展启动时间。一旦集群完成高负载处理或终止,从池中借用的虚拟机会被归还到池中,可以被下一个集群使用。更多关于池的信息,请访问:docs.databricks.com/clusters/instance-pools/index.html
。
Databricks作业允许用户在特定的时间表上自动执行代码。它还提供了许多其他有价值的配置选项,例如在代码执行失败时可以重试的次数,并能够在失败时设置警报。你可以在这里阅读更多关于作业的信息:docs.databricks.com/data-engineering/jobs/jobs-quickstart.html
。该链接适用于在 AWS 上部署的 Databricks 工作区;不过,你可以点击更改云标签以匹配你的部署:
图 2.7 – 选择与您云相关文档的下拉菜单
现在,让我们重点关注创建 集群标签。
如果你来自机器学习领域,且大部分工作都是在笔记本或单独的虚拟机上完成的,那么 Databricks 提供了一种简单的方式来开始,提供单节点模式。在这种情况下,你将在单节点集群上使用 Databricks 的所有优势。现有的非分布式代码应该能在该集群上直接运行。例如,以下代码将在驱动节点上以非分布式方式运行:
from sklearn.datasets import load_iris # Importing the Iris datasetfrom sklearn.model_selection import train_test_split # Importing train_test_split function
from sklearn.linear_model import LogisticRegression # Importing Logistic Regression model
from sklearn.metrics import accuracy_score # Importing accuracy_score metric
# Load the Iris dataset
iris = load_iris()
X = iris.data # Features
y = iris.target # Labels
# Split the dataset into training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Initialize the logistic regression model
model = LogisticRegression()
# Train the model
model.fit(X_train, y_train)
# Make predictions on the test set
y_pred = model.predict(X_test)
# Calculate the accuracy of the model
accuracy = accuracy_score(y_test, y_pred)
print("Accuracy:", accuracy)
注意
通常,集群指的是一组以分布式方式处理数据的机器。在单节点集群的情况下,一台虚拟机(VM)运行所有进程,而在常规集群中则有多个虚拟机共同运行。
在 Databricks 环境中启动集群非常简单。本书中提供的所有代码都可以在单节点集群上运行。要启动单节点集群,按照以下步骤操作:
-
给集群命名。
-
将集群模式更改为单节点。
-
将最新的机器学习运行时设置为Databricks 运行时版本。
-
点击创建集群:
图 2.8 – 新建集群屏幕
这将启动集群配置过程。你可以阅读一些高级设置,如添加标签、使用初始化脚本以及通过 JDBC 连接到此集群等内容。
Databricks Runtime是一个强大的平台,通过提高 Spark 作业的性能、安全性和可用性,增强了大数据分析功能。凭借优化的 I/O、增强的安全性和简化的操作等功能,它提供了一个全面的解决方案。它有多种版本,包括ML和Photon,以满足特定需求。Databricks Runtime 是高效运行大数据分析工作负载的理想选择。Databricks Runtime 由 Delta Lake 提供支持,它无缝地集成了批处理和流数据,支持近实时分析。Delta Lake 能够跟踪数据的版本变更,对于重现机器学习模型训练和实验至关重要。这确保了数据的一致性,并在你的工作流程中提供了可重现性。你可以在这里阅读更多关于 Databricks Runtime 的内容:docs.databricks.com/runtime/index.html
。
作为 Databricks 上的机器学习实践者,你将使用 ML 运行时。Databricks Runtime ML 是一个预构建的机器学习基础设施,它与 Databricks 工作区的功能集成。它提供了流行的机器学习库,如 TensorFlow 和 PyTorch,分布式训练库,如 Horovod,以及预配置的 GPU 支持。通过更快的集群创建和与已安装库的兼容性,它简化了机器学习和深度学习任务的扩展。此外,它还提供了数据探索、集群管理、代码和环境管理、自动化支持,以及集成的 MLflow 用于模型开发和部署。
Databricks 提供了三种不同的集群访问模式及其特定的推荐使用案例模式。所有这些集群访问模式都可以在多节点模式(集群有一个专用的驱动节点和一个或多个执行节点)或单节点模式(集群仅有一个节点;驱动程序和执行程序都在一个节点上运行)下使用。
单一用户
此模式建议用于单一用户和可以使用 Python、Scala、SQL 和 R 开发的数据应用。集群会在 120 分钟无活动后终止,标准集群是默认的集群模式。最终用户也可以通过 Databricks 作业使用调度活动执行笔记本。最好将不同的数据处理管道划分到独立的标准集群中。划分数据管道可以防止一个集群的失败影响到另一个集群。由于 Databricks 按秒计费,这种方法是可行的并被广泛使用。具有此访问类型的集群支持机器学习工作负载。
共享
当多个用户尝试使用同一个集群时,此模式是理想的选择。它能够提供最大化的资源利用率,并且在多用户场景下具有较低的查询延迟要求。数据应用可以使用 Python 和 SQL 开发,但不能使用 R 和 Scala。这些集群提供用户隔离,并且也支持机器学习工作负载。
无隔离共享
这种类型的集群仅面向管理员用户。我们不会过多讨论此类访问,因为该集群类型不支持 ML 用例。
你可以在这里阅读更多关于用户隔离的内容:docs.databricks.com/notebooks/notebook-isolation.html
。
让我们来看看单节点集群,因为这就是你将用来运行本书中共享代码的集群类型。
单节点集群
单节点集群没有工作节点,所有的 Python 代码都在驱动节点上运行。默认情况下,这些集群会在 120 分钟没有活动后自动终止,适用于构建和测试小型数据管道,以及进行轻量级的探索性数据分析(EDA)和 ML 开发。支持 Python、Scala、SQL 和 R。
如果你想使用运行时中未包含的特定库,我们将在本章的 库 部分探讨安装所需库的各种选项。
探索笔记本
如果你熟悉Jupyter和IPython 笔记本,那么 Databricks 笔记本会显得非常熟悉。Databricks 笔记本开发环境由多个单元组成,用户可以在其中互动式地编写 R、Python、Scala 或 SQL 代码。
Databricks 笔记本还具有其他功能,如与 Spark UI 的集成、强大的集成可视化、版本控制以及 MLflow 模型跟踪服务器。我们还可以对笔记本进行参数化,并在执行时向其传递参数。
我们将在后续详细介绍笔记本,因为本书中提供的代码示例利用了 Databricks 笔记本环境。有关笔记本的更多详细信息,请访问docs.databricks.com/notebooks/index.html
:
图 2.9 – Databricks 笔记本
让我们看看 数据 标签上的下一个功能,也称为 Databricks 元数据存储。
探索数据
默认情况下,当部署新的工作区时,它会附带一个托管的 Hive 元数据存储。元数据存储允许你以外部表的形式注册各种格式的数据集,如逗号分隔值(CSV)、Parquet、Delta 格式、文本或JavaScript 对象表示法(JSON)(docs.databricks.com/data/metastores/index.html
)。我们在这里不会深入讨论元数据存储的细节:
图 2.10 – 数据标签
如果您不熟悉“元存储”这个术语,也没关系。简单来说,它类似于关系数据库。在关系数据库中,有数据库,然后是表名和模式。最终用户可以使用 SQL 与存储在数据库和表中的数据交互。同样,在 Databricks 中,最终用户可以选择注册存储在云存储中的数据集,以便它们可以作为表格使用。您可以在这里了解更多:docs.databricks.com/spark/latest/spark-sql/language-manual/index.html
。
Hive 元存储通过利用工作区内本地用户的表访问控制列表提供了一种实现访问控制的方法。然而,为了增强数据访问治理并确保对各种资产(如部署的模型和 AI 资产)进行统一控制,Databricks 引入了 Unity Catalog 作为最佳实践解决方案。这使得跨多个工作区进行全面的管理和治理成为可能。
让我们更详细地了解 Unity Catalog。
Unity Catalog 是湖仓中数据和 AI 资产的统一治理解决方案。它提供了跨 Databricks 工作区的集中访问控制、审计、血缘分析和数据发现功能:
图 2.11 – Unity Catalog 与工作区的关系
下面是 Unity Catalog 的一些关键特性:
-
定义一次,处处安全:Unity Catalog 从一个地方管理跨所有工作区和角色的数据访问策略
-
符合标准的安全模型:Unity Catalog 的安全模型基于标准 ANSI SQL,并允许管理员在现有数据湖中授予权限
-
内建审计和血缘分析:Unity Catalog 捕获用户级审计日志和血缘数据,跟踪数据资产在所有语言和角色中的创建和使用情况
-
数据发现:Unity Catalog 提供了一个搜索界面,帮助数据消费者找到数据,并允许用户标记和记录数据资产
-
系统表(公共预览):Unity Catalog 提供操作数据,包括审计日志、可计费使用情况和血缘分析
让我们了解 Unity Catalog 对象模型的具体样子:
图 2.12 – Unity Catalog 对象模型
Unity Catalog 的主要数据对象层次结构从元存储到表格流动:
-
元存储:元数据的顶级容器。每个元存储公开一个三级命名空间(目录.模式.表),用于组织您的数据。
-
目录:这是对象层次结构的第一层,用于组织您的数据资产。
-
模式:也称为数据库,模式包含表格和视图。
-
表格:对象层次结构中最低级别是表格和视图。
如前所述,深入了解 Unity Catalog 是一个非常庞大的话题,超出了本书的范围。Unity Catalog 为 Databricks 工作区中的数据和 AI 资产提供集中式治理、审计和数据发现功能。它提供基于 ANSI SQL 的安全模型、自动捕获用户级审计日志和数据血缘关系、以及层级化的数据组织系统。它还支持多种数据格式、先进的身份管理、专门的管理员角色用于数据治理,并兼容 Databricks Runtime 11.3 LTS 或更高版本。
想要更全面了解 Unity Catalog,请访问 docs.databricks.com/data-governance/unity-catalog/index.html
。
到目前为止,我们所覆盖的所有功能都是 Databricks 针对特定角色的标准功能。
以下三个功能——实验、特征存储和模型——对于机器学习角色至关重要。
让我们一一查看这些功能。
探索实验
正如其名所示,实验是所有与业务问题相关的模型训练的集中位置,用户可以访问这些实验。用户可以为实验定义自己的名称,或者使用系统自动生成的默认名称,并用它来训练不同的机器学习模型。Databricks UI 中的实验来自将 MLflow 集成到平台中。我们将在接下来的章节中深入探讨 MLflow,以了解更多细节;然而,首先了解 MLflow 的基本概念及一些特定术语是非常重要的。
MLflow 是一个开源平台,用于管理端到端的机器学习生命周期。以下是 MLflow 的关键组件:
-
跟踪:这允许你跟踪实验,记录和比较参数与结果。
-
模型:此组件有助于管理和部署来自各种机器学习库的模型,支持多种模型服务和推理平台。
-
项目:这允许你以可重用、可复制的形式打包机器学习代码,以便与其他数据科学家共享或转移到生产环境中。
-
模型注册表:这是一个集中式的模型存储库,用于管理模型的完整生命周期阶段转换:从预发布到生产,并具备版本控制和注释功能。Databricks 在 Unity Catalog 中提供了一个托管版本的模型注册表。
-
模型服务:这允许你将 MLflow 模型作为 REST 端点进行托管。
还有一些专属于 MLflow 的术语:
-
运行:运行表示训练机器学习模型的具体实例。它包括与训练过程相关的参数、度量、工件和元数据。
-
实验:实验作为一个容器,用于组织和跟踪机器学习实验的结果。它由多个运行组成,便于不同方法的比较和分析。
-
参数:参数是指在训练机器学习模型过程中可以调整的可配置值。这些值影响模型的行为和性能。
-
度量:度量是用于评估机器学习模型性能的定量指标。度量提供了有关模型在特定任务或数据集上表现如何的洞察。
-
工件:工件是指在机器学习实验期间生成的任何输出。这可以包括文件、模型、图像或捕获实验结果或中间阶段的其他相关数据。
-
项目:项目包括重现机器学习实验所需的代码、数据和配置。它提供了一种结构化和组织化的方法,用于管理特定机器学习工作流程的所有组件。
-
模型:模型表示经过训练的机器学习模型,可用于基于训练数据学到的模式和信息进行预测或执行特定任务。
-
模型注册表:模型注册表作为集中存储和管理机器学习模型的库。它为不同模型版本及其关联的元数据提供版本控制、跟踪和协作能力。
-
后端存储:后端存储负责存储诸如运行、参数、度量和标签等 MLflow 实体。它为管理实验数据提供了基础存储基础设施。
-
工件存储:工件存储负责存储在机器学习实验期间生成的工件。这可能包括文件、模型、图像或任何在实验过程中生成的其他相关数据。
-
风味:风味代表一种标准化的 ML 模型打包方式,使其可以轻松被特定工具或平台消费。风味在部署和服务模型时提供了灵活性和互操作性。
-
用户界面(UI):UI 指的是 MLflow 提供的图形界面,允许用户通过直观界面与实验结果进行交互和可视化,跟踪运行并管理模型。
MLflow 还采用了其他术语,但此处提到的是一些最常用的。有关详细信息,请参阅 MLflow 文档:mlflow.org/docs/latest/index.html
。
Databricks AutoML 与 MLflow 完全集成,因此生成的所有模型训练和工件都会自动记录在 MLflow 服务器中:
图 2.13 – 实验选项卡
最终用户也可以利用 Databricks AutoML 来为其机器学习问题建模。Databricks 在其 AutoML 能力中采用了一种不同的方法,称为玻璃盒 AutoML。
Databricks AutoML 通过自动生成全面的笔记本简化了 ML 从业者的工作流程。这些笔记本涵盖了特征工程和模型训练所需的所有代码,涵盖了多种 ML 模型和超参数的组合。此功能使 ML 从业者能够深入检查生成的代码,并获得对过程的更深层次理解。
Databricks AutoML 当前支持分类、回归和预测模型。有关 AutoML 可以使用哪些算法来创建模型的完整列表,请访问 docs.databricks.com/applications/machine-learning/automl.html#automl-algorithms
:
图 2.14 – 默认实验默认与 Python 笔记本连接
MLflow 是 Databricks 内部开发的,用于简化端到端的 ML 生命周期和 MLOps。自 MLflow 发布以来,它已经被广泛采用并得到了开源社区的支持。
现在,让我们来看看特征存储。
发现特征存储
特征存储是最新 Databricks ML 工作空间中的一个相对较新但稳定的版本。许多已经拥有成熟 ML 流程的组织,如 Uber、Facebook、DoorDash 等,已经在内部实现了他们的特征存储。
ML 生命周期管理和工作流程是复杂的。Forbes 进行了一项调查(www.forbes.com/sites/gilpress/2016/03/23/data-preparation-most-time-consuming-least-enjoyable-data-science-task-survey-says
),并与数据科学家进行了交流,发现管理数据是他们日常工作中最昂贵且最耗时的操作。
数据科学家需要花费大量时间查找数据、清洗数据、进行 EDA,然后进行特征工程以训练他们的 ML 模型。这是一个迭代过程。为了使这个过程可以重复,需要投入的努力是一个巨大的挑战。这就是特征存储的作用所在。
Databricks 特征存储采用开源 Delta 格式进行标准化,这使得数据科学家能够像管理模型、笔记本或工作任务的访问权限一样管理特征。
Databricks 特征存储有几个独特之处:
-
它使用 Delta Lake 存储特征表。这使得最终用户能够从 Databricks 外部的任何受支持语言和连接器中读取数据。更多信息请访问:
docs.delta.io/latest/delta-intro.html
。 -
Databricks ML 工作区中的集成 Feature Store UI 提供了端到端的可追溯性和特征生成的溯源信息,以及哪些下游模型在统一视图中使用了这些特征。我们将在第三章中更详细地探讨这一点。
Databricks Feature Store 还与 MLflow 无缝集成。这使得 Databricks Feature Store 能够利用 MLflow 特征管道的所有优点,并生成特征并将其以 Delta 格式写入特征表。Feature Store 具有自己的通用模型包装格式,与 MLflow Models 组件兼容,这使得模型能够明确了解哪些特征被用于训练模型。这种集成使我们能够简化 MLOps 管道。
客户端可以通过批处理模式或在线模式调用服务端点,模型将自动从 Feature Store 中获取最新的特征并提供推理服务。我们将在接下来的章节中看到相关的实际案例。
你也可以在这里了解更多关于 Databricks Feature Store 当前状态的信息:docs.databricks.com/machine-learning/feature-store/index.html
最后,我们来讨论一下模型注册表。
发现模型注册表
模型是一个完全托管且与 Databricks ML 工作区集成的 MLflow 模型注册表。该注册表拥有一套 API 和一个 UI,方便组织中的数据科学家进行协作并全面管理 MLflow 模型。数据科学家和机器学习工程师可以在任何受支持的 ML 框架中开发模型(mlflow.org/docs/latest/models.html#built-in-model-flavors
),并将其打包成通用的 MLflow 模型格式:
图 2.15 – 模型标签页
模型注册表提供了管理版本、标签以及在不同环境之间进行状态转换的功能(将模型从预发布阶段迁移到生产环境再到归档):
图 2.16 – 已注册模型标签页
在我们继续之前,还有一个重要的功能需要理解:Databricks 的库功能。这个功能允许用户将第三方或自定义代码引入 Databricks 笔记本和在集群上运行的作业中。
库
库是任何编程生态系统中的基础构建模块。它们类似于工具箱,包含了预编译的例程,提供增强的功能并帮助优化代码效率。在 Databricks 中,库用于将第三方或自定义代码引入到在集群上运行的笔记本和作业中。这些库可以用多种语言编写,包括 Python、Java、Scala 和 R。
存储库
在存储方面,通过库 UI 上传的库存储在Databricks 文件系统(DBFS)根目录中。然而,所有工作区用户都可以修改存储在 DBFS 根目录中的数据和文件。如果需要更安全的存储选项,您可以选择将库存储在云对象存储中,使用库包仓库,或者将库上传到工作区文件。
管理库
在 Databricks 中,库的管理可以通过三种不同的界面进行:工作区 UI、命令行界面(CLI)或 Libraries API。每个选项都适应不同的工作流程和用户偏好,选择通常取决于个人使用场景或项目需求。
Databricks Runtime 和库
Databricks Runtime 配备了许多常见的库。要查找您的运行时中包含哪些库,您可以参考 Databricks Runtime 发行说明中的系统环境子部分,检查您的具体运行时版本。
请注意,当您的笔记本或作业完成处理时,Python 的atexit
函数不会被 Databricks 调用。如果您正在使用一个注册了atexit
处理程序的 Python 库,确保您的代码在退出前调用所需的函数非常重要。另外,Databricks Runtime 正在逐步淘汰使用 Python eggs,并最终会移除它们;建议使用 Python wheels 或从 PyPI 安装包作为替代方案。
库使用模式
Databricks 提供三种库安装模式:集群安装、笔记本范围的库和工作区库:
-
集群库:这些库可供所有在特定集群上运行的笔记本使用。
-
笔记本范围的库:这些库适用于 Python 和 R,创建一个与笔记本会话范围相关的环境,不会影响在同一集群上运行的其他笔记本。它们是临时的,每个会话需要重新安装。
-
工作区库:这些库充当本地仓库,您可以从中创建集群安装的库。它们可以是贵组织编写的自定义代码,或者是贵组织偏好的开源库的特定版本。
接下来让我们讨论一下 Unity Catalog 的限制。
Unity Catalog 限制
使用 Unity Catalog 时存在一些限制。有关更多细节,您应该参考集群 库部分。
库的安装来源
集群库可以直接从公共仓库安装,如 PyPI、Maven 或 CRAN。或者,它们可以来自云对象存储位置、DBFS 根目录中的工作区库,甚至可以通过从本地机器上传库文件进行安装。通过上传直接安装的库存储在 DBFS 根目录中。
对于大多数使用场景,我们将使用笔记本范围的库。您可以使用%pip
magic
命令安装笔记本范围的库。
以下是一些在笔记本中使用 %pip
安装笔记本作用域库的方法:
-
%pip install <package-name>
用于笔记本作用域的库,或者选择 PyPI 作为集群库的来源 -
%pip install <package-name> --index-url <mirror-url>
用于笔记本作用域的库 -
%pip install git+https://github.com/<username>/<repo>.git
用于笔记本作用域的库,或者选择 PyPI 作为来源,并指定仓库 URL 作为集群库的包名 -
%pip install dbfs:/<path-to-package>
用于笔记本作用域的库,或者选择 DBFS/S3 作为集群库的来源
现在,让我们总结一下本章内容。
总结
本章中,我们简要了解了 Databricks ML 工作区的所有组件。这将帮助我们更实际地使用这些组件,从而在 Databricks 环境中高效地训练和部署 ML 模型,解决各种 ML 问题。
在下一章中,我们将开始处理客户流失预测问题,并在 Databricks 特征存储中注册我们的第一个特征表。
深入阅读
要了解更多本章涉及的主题,请查阅以下内容:
-
Databricks 库:
docs.databricks.com/libraries/index.html
-
Databricks 笔记本:
docs.databricks.com/notebooks/index.html
第二部分:ML 管道组件与实现
在本节结束时,您将对 Databricks ML 体验中的每个 ML 组件有清晰的理解,并能够在项目中自如地使用它们。
本节包含以下章节:
-
第三章,利用特征存储
-
第四章,了解 Databricks 上的 MLflow 组件
-
第五章,使用 Databricks AutoML 创建基准模型
第三章:使用特征存储
在上一章中,我们简要介绍了什么是特征存储,以及Databricks Feature Store在其独特性方面的优势。
本章将采取更为实践的方式,利用 Databricks Feature Store 注册我们的第一个特征表,并讨论与 Databricks Feature Store 相关的概念。
我们将涵盖以下主题:
-
深入了解特征存储及其解决的问题
-
在 Databricks 平台上发现特征存储
-
在 Databricks Feature Store 中注册你的第一个特征表
技术要求
所有代码都可以在 GitHub 仓库github.com/PacktPublishing/Practical-Machine-Learning-on-Databricks
中找到,且是自包含的。要执行这些笔记本,你可以直接将代码仓库导入到你的 Databricks 工作区,使用Repos功能。我们在第二章中讨论过 Repos。
需要具备Delta格式的基本知识。如果你是 Delta 格式的新人,可以在继续之前查看docs.databricks.com/en/delta/index.html
和docs.databricks.com/en/delta/tutorial.html
。
深入了解特征存储及其解决的问题
随着组织中的更多团队开始使用人工智能(AI)和机器学习(ML)来解决各种业务应用场景,建立一个集中的、可重用的、易于发现的特征库变得尤为必要。这个库被称为特征存储(Feature Store)。
所有经过整理的特征都存储在集中式、受管理、访问受控的存储中,例如整理过的数据湖。不同的数据科学团队可以根据需求被授予访问特征表的权限。像企业数据湖一样,我们可以追踪数据的血缘关系;同样,我们也可以追踪在 Databricks Feature Store 中注册的特征表的血缘关系。我们还可以查看所有消费已注册特征表中特征的下游模型。
在大型组织中,有数百个数据科学团队在解决不同的业务问题。每个团队可能都有自己的领域知识和专业技能。特征工程的实施通常需要大量的计算处理。如果没有特征存储,新加入的数据科学团队将很难重复使用其他团队创建和整理的特征。
我们可以将特征存储的工作流类比于 ETL 工作流,后者针对特定的 BI 或分析应用场景。将数据写入特征存储表的工作流针对的是特征工程过程,需要在数据湖中的整理数据集上执行这些过程,然后才能训练机器学习模型。
你可以像常规的 ETL 操作一样调度和监控特征表工作流的执行。
特性存储还通过提供一个跨组织的特性中央仓库,解决了模型训练和推理代码之间的偏差问题。在模型训练和推理时使用相同的特性工程逻辑。
让我们看看特性存储是如何构建并与 Databricks 工作空间集成的。
在 Databricks 平台上发现特性存储
每个 Databricks 工作空间都有自己的特性存储。在本书编写时,Databricks 特性存储仅支持 Python API。最新的 Python API 参考可以在 docs.databricks.com/applications/machine-learning/feature-store/python-api.html
找到。
Databricks 特性存储与管理的 MLFlow及其他 Databricks 组件完全集成。这使得通过 MLFlow 部署的模型可以在训练和推理时自动检索特性。定义特性表并在模型训练和推理中使用它的具体步骤将在接下来的部分中介绍。
让我们来看一些与 Databricks 特性存储相关的关键概念和术语。
特性表
正如名称所示,特性存储存储由数据科学家在进行特性工程时为特定问题生成的特性。
这些特性可能来自数据湖中一个或多个清理过的表。Databricks 中的特性表包含两个主要组件:
-
元数据:元数据跟踪用于创建特性表的数据来源,哪些笔记本和定时任务将数据写入特性表,以及其频率。元数据还跟踪使用该特性表的下游 ML 模型。这提供了数据的溯源。
-
生成的特性数据:在批处理和流式推理的情况下,底层生成的特性 DataFrame 被写入作为 Delta 表到离线特性存储中。Databricks 为你管理这个离线特性存储。相比之下,特性表被写入到支持的关系数据库管理系统(RDBMS)中,以用于在线特性存储。在线特性存储不由 Databricks 管理,设置时需要一些额外的步骤。你可以在进一步阅读部分找到相关链接,以帮助你设置在线特性存储。
在继续之前,让我们简要了解不同类型的推理模式,以及 Databricks 特性存储在每种场景中的优势。
-
批量推理:批量推理涉及对大量数据进行一次性预测,通常是在间隔时间或按计划执行时进行。在 Databricks 中,你可以使用如Apache Spark等技术设置批处理作业,以处理和预测输入数据。批量推理适用于那些预测时效性不那么关键,可以等待结果的场景。例如,这可以用于客户细分,其中预测是定期进行的。此场景由离线特征存储支持。
- Databricks 特征存储通过提供集中式的特征数据存储库来增强批量推理。与其为每个批处理作业重新计算特征,特征存储允许你存储和管理预计算的特征。这减少了计算时间,确保在每次批处理运行中为你的模型提供一致且准确的特征。
-
流式推理:流式推理涉及在数据实时到达时进行处理和预测,而无需等待整个数据集的收集。Databricks 通过如 Apache Spark 的结构化流式处理等工具支持流式数据处理。流式推理在需要快速响应变化数据的场景中非常有价值,例如在欺诈检测中,及时采取行动至关重要。此场景由离线特征存储支持。
- 特征存储在流式场景中发挥关键作用,提供可靠的特征数据源。当新数据流入时,特征存储可以提供预测所需的特征,确保为模型提供一致且最新的输入。这简化了流式管道,因为特征准备与实时推理过程解耦。
-
实时推理:实时推理将流式推理进一步发展,通过在新数据到达时立即提供预测。在推荐系统等应用中,这一点尤为重要,因为用户期望对其行为立即做出响应。此场景需要在线特征存储。
- 对于实时推理,特征存储确保特征数据随时可用,以便快速预测。特征存储与实时推理管道的集成使得可以低延迟访问特征,从而有助于快速和准确的预测。这对于需要迅速决策的应用至关重要。
每个特征表都有一个主键,唯一标识一行数据。Databricks 特征存储也允许定义复合主键。
新数据可以通过定期执行的 ETL 管道以批量方式或利用结构化流式 API(docs.databricks.com/spark/latest/structured-streaming/index.html
)以持续方式写入特征表中。
在 Databricks 中注册新特征表的工作流如下:
-
创建一个数据库,用于存储我们的特征表。
-
将特征工程逻辑编写为一个函数,该函数返回一个 Apache Spark 数据框(
spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrame.html
)。此数据框还应为数据框中的每条记录生成一个唯一的主键。主键可以包含多个列。 -
实例化一个
FeatureStoreClient
对象,并使用create_table
(在 DB ML Runtime 10.2 及以上版本支持)在特征存储中定义特征表。此时,特征表中没有存储数据。如果我们初始化一个额外的df
参数,并将其赋值为特征工程数据框,我们可以跳过 步骤 4。 -
使用
write_table
方法将特征工程数据集写入定义的特征表中。write_table
方法提供了两种模式:要么完全覆盖现有特征表,要么根据定义的查找键更新某些记录。
本章提供的代码示例将通过上述步骤并使其更容易理解。在深入研究代码之前,我们需要了解一些与特征存储相关的概念。
我们将在《MLFlow》一章中进一步探讨如何从特征表中读取数据。我们将重用本章中创建的特征表来预测银行客户流失。
离线存储
Databricks 离线特征存储由 Delta 表支持,主要用于模型训练、批量推理和特征发现。
Delta 表允许用户根据主键在此模式下更新特征值。利用 Delta 格式在 ML 的背景下也提供了额外的优势:
-
使用
timestampAsOf
来读取某些历史数据:# Reading data from a Delta table as it appeared at a specific timestampdf = spark.read.format("delta").option("timestampAsOf", "2021-01-01").load("/path/to/delta-table")
-
Delta API 中的
history()
函数(docs.delta.io/latest/index.html
):from delta.tables import *deltaTable = DeltaTable.forPath(spark, write_path)fullHistoryDF = deltaTable.history()# get the full history of the table to pick the versiondisplay(fullHistoryDF)
要从特定版本的表中加载数据,我们可以指定
versionAsOf
选项:## Specifying data version to use for model trainingversion = 1df_delta = spark.read.format('delta').option('versionAsOf', version).load(write_path)
这样,你就可以在数据的不同版本上训练模型并保持数据血统。
在线存储
在使用特征存储进行实时推理时,特征表需要存储在低延迟存储中,如关系数据库。
如果你必须在在线和离线特征存储中都能使用特征,你可以将离线存储作为流式数据源来更新在线存储的特征表。
训练集
在训练 ML 模型时,你可能希望将来自多个特征表的数据结合起来。每个特征表都需要有唯一的 ID 或主键,这些 ID 或主键将在模型训练和推理时用于连接和提取来自多个特征表的相关特征到 训练集 构建中。
训练集使用一个名为FeatureLookup
的对象,它的输入包括特征表名称、我们需要从特征表中检索的特征名称,以及查找键(s)。查找键(s)用于在我们定义多个FeatureLookup
以生成训练集时,从不同的特征表中连接特征。
在本章附带的笔记本中,我们将通过示例代码展示如何将一个欺诈检测数据集注册为 Databricks Feature Store 中的特征表。在第五章中,使用 Databricks AutoML 创建基准模型,我们将利用 AutoML 概述中的特征表,构建一个流失预测模型,并展示 Databricks 环境中集成的 MLFlow 的各种组件。
模型打包
FeatureStoreClient
API(docs.databricks.com/en/dev-tools/api/python/latest/feature-store/client.html
)提供了一个名为log_model
的方法,允许机器学习模型保留用于训练模型的特征的引用。这些特征存储在 Databricks Feature Store 中作为特征表。ML 模型可以根据推理时提供的主键(s)从特征表中检索必要的特征。在批量和流式推理模式下,特征值从离线存储中检索。在实时推理模式下,特征值则从在线存储中检索。
注意
在编写本书时,Databricks Feature Store 仅支持 Python 语言。你可以使用你喜欢的库,如sklearn
和 pandas,进行特征工程;但是,在将表格写出为特征表之前,它需要转换为PySpark DataFrame。PySpark 是 Spark 分布式处理引擎的 Python 封装(spark.apache.org/docs/latest/api/python/
)。
让我们深入一个动手实践的例子,带你一步步完成在 Databricks Feature Store 中注册第一个特征表的过程。
我们将使用的数据集来自Kaggle,在进行一些特征工程后,我们将在 Databricks Feature Store 注册该数据集。
在 Databricks Feature Store 中注册你的第一个特征表
在开始之前,代码需要从与本书配套的 Git 仓库中下载(github.com/debu-sinha/Practical_Data_Science_on_Databricks.git
)。
我们将使用 Databricks 的仓库功能来克隆 GitHub 仓库。
要克隆代码仓库,完成以下步骤:
- 点击Repos标签并选择你的用户名:
图 3.1 – 显示 Repos 标签页的截图
重要说明
由于最近的用户界面更新,'Repos' 部分已被移动,现在可以通过点击 'Workspaces' 图标访问,以下图所示。
尽管进行了此更改,本章中概述的工作流程依然适用。
- 右键点击并添加仓库:
图 3.2 – 显示如何克隆本章代码(步骤 2)的截图
- 将链接粘贴到 Git 仓库 URL 字段中,然后点击 创建:
图 3.3 – 显示如何克隆本章代码(步骤 3)的截图
- 在克隆的仓库中,点击
Chapter 03
,然后在其中选择churn-analysis
笔记本:
图 3.4 – 显示如何克隆本章代码(步骤 4)的截图
当你第一次打开笔记本时,它将处于分离状态。如果你还没有配置集群,请参考 第二章中的 探索集群 部分。
你可以在以下截图中看到笔记本:
图 3.5 – 显示笔记本初始状态的截图
- 配置好集群后,你可以将其附加到笔记本:
图 3.6 – 显示将笔记本附加到可用集群列表的下拉菜单的截图
所有代码已在 Databricks ML Runtime 10.4 LTS 上进行测试。建议用户使用配置了 ML Runtime 10.4 LTS 或更高版本的集群。
- 从下拉菜单中选择一个选项:
图 3.7 – 显示笔记本附加到集群并处于准备状态的截图
现在,你可以开始执行笔记本中的代码了:
-
笔记本中的前几个单元描述了我们正在使用的数据集以及如何将其读取为 Spark DataFrame。我们也可以将数据导入为 pandas DataFrame。Databricks 提供了一个方便的显示功能,可以可视化加载到 pandas 或 Spark DataFrame 中的数据:
import osbank_df = spark.read.option("header", True).option("inferSchema", True).csv(f"file:{os.getcwd()}/data/churn.csv")display(bank_df)
-
下一段代码介绍了创建特征表的步骤。第一步是定义一个数据库,用来存储我们定义的、以 Delta 表为基础的特征表。我们还定义了一种方法来执行一些基本的特征工程:
DATABASE_NAME = "bank_churn_analysis"# setup database and tmp space that will hold our Feature tables in Delta format.spark.sql(f"CREATE DATABASE IF NOT EXISTS {DATABASE_NAME}")dbutils.fs.mkdirs(f"/tmp/{DATABASE_NAME}")
-
下面的代码块定义了一个基本函数,用于对输入的 Spark DataFrame 执行特征工程。
在继续之前,我想强调一个强大的库称为
pyspark.pandas
。作为机器学习实践者,你可能熟悉使用 pandas (pandas.pydata.org/docs/#
) 库来操作数据。它有一个很大的缺点,即它不具备可扩展性。使用 pandas API 进行的所有处理都在单台机器上进行,如果你的数据无法放入单台机器,你就会陷入困境。这就是 Apache Spark 可以帮助的地方。Apache Spark 专为处理大量数据而构建,它将大量数据划分为单个单位,并在集群的多个节点上分发处理。随着要处理的数据量增加,你可以简单地向集群添加更多节点,如果你的数据没有任何倾斜,数据处理流水线的性能将保持不变。然而,有一个很大的挑战:许多机器学习从业者不熟悉 Spark 库。这正是开发
pyspark.pandas
(spark.apache.org/docs/latest/api/python/reference/pyspark.pandas/index.html
) 库的核心原因。该库旨在弥合 pandas 库和 Apache Spark 之间的差距。pyspark.pandas
库的核心在于它能够在 Apache Spark 的领域内提供类似 pandas 的 API。这一创新将两个世界的优势结合在一起,使用户在使用熟悉的 DataFrame API 的同时,利用 Spark 的可扩展性和性能优势。对于熟悉 pandas 的用户来说,转向pyspark.pandas
是无缝的,为简化采纳过程铺平了道路。然而,重要的是要记住,并非所有 pandas API 都在pyspark.pandas
API 中实现,可能会导致兼容性问题。如果你真的需要使用某些 pandas API 功能,而
pyspark.pandas
尚未提供,你可以使用一个名为toPandas()
的方法(spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.DataFrame.toPandas.html?highlight=topandas
)。作为最佳实践,在使用 pandas API 之前,尽量使用 PySpark/pyspark.pandas
API。有关最佳实践的更多信息,请参阅spark.apache.org/docs/latest/api/python/user_guide/pandas_on_spark/best_practices.html?highlight=pandas#use-pandas-api-on-spark-directly-whenever-possible
。import pyspark.pandas as psdef compute_features(spark_df): # Convert to pyspark.pandas DataFrame # https://spark.apache.org/docs/3.2.0/api/python/user_guide/pandas_on_spark/pandas_pyspark.html#pyspark ps_df = spark_df.to_pandas_on_spark() #https://spark.apache.org/docs/3.2.0/api/python/reference/pyspark.pandas/api/pyspark.pandas.DataFrame.drop.html#pyspark.pandas.DataFrame.drop # drop RowNumber & Surname column ps_df = ps_df.drop(['RowNumber', 'Surname'], axis=1) # OHE (One hot encoding) ohe_ps_df = ps.get_dummies( ps_df, columns=["Geography", "Gender"], dtype="int", drop_first=True ) ohe_ps_df.columns = ohe_ps_df.columns.str.replace(r' ', '', regex=True) ohe_ps_df.columns = ohe_ps_df.columns.str.replace(r'(', '-', regex=True) ohe_ps_df.columns = ohe_ps_df.columns.str.replace(r')', '', regex=True) return ohe_ps_df
-
下一个代码块执行特征工程,利用前一节定义的函数,并显示结果:
bank_features_df = compute_features(bank_df)display(bank_features_df)
-
接下来,我们将初始化
FeatureStoreClient
,注册表格,并使用create_table
函数定义特征表的结构:# Our first step is to instantiate the feature store client using `FeatureStoreClient()`.from databricks.feature_store import FeatureStoreClientfs = FeatureStoreClient()bank_feature_table = fs.create_table( name=f"{DATABASE_NAME}.bank_customer_features", # the name of the feature table primary_keys=["CustomerId"], # primary key that will be used to perform joins schema=bank_features_df.spark.schema(), # the schema of the Feature table description="This customer level table contains one-hot encoded categorical and scaled numeric features to predict bank customer churn.")
-
一旦我们定义了特征表的结构,就可以使用
write_table
函数向表中填充数据:fs.write_table(df=bank_features_df.to_spark(), name=f"{DATABASE_NAME}.bank_customer_features", mode="overwrite")
如果你只想更新某些记录,可以选择
merge
作为选项,而不是覆盖原有数据。实际上,当你调用
create_table
方法并传入源 Spark DataFrame 作为feature_df
参数时,可以填充特征表。当你已经有一个准备好的 DataFrame 用来初始化特征表时,这种方法非常有用。 -
现在,我们可以在集成的特征存储 UI 中查看我们的特征表。我们可以看到谁创建了特征表,以及哪些数据源填充了特征表。特征存储 UI 提供了很多关于特征表的重要信息:
图 3.8 – 显示特征存储的截图
- 我们可以通过 Databricks 的用户界面检查特征表的创建时间以及创建者。此信息对于跟踪数据来源和了解组织内的数据流向非常有价值。此外,UI 还显示其他相关信息,例如表格最后一次刷新时间,帮助了解表格数据的最新状态:
图 3.9 – 显示特征表的所有者、主键、创建日期和最后更新时间的截图
此外,UI 还提供了有关表格分区和主键的详细信息。分区对于查询优化至关重要,它们通过根据特定列值将表格划分为不同的子集,从而实现更高效的数据检索。而主键则充当表中每一行的唯一标识符,确保数据完整性,并便于快速查找。
- 在生产环境中,如果我们的特征表通过笔记本定期填充,我们还可以查看历史更新:
图 3.10 – 显示特征表来源的截图
- 最后,我们还可以查看特征表中每个特征的数据类型:
图 3.11 – 显示特征表各列及其数据类型的截图
该笔记本有详细的文档,指导你完成从导入到 Databricks 到编写第一个特征表所需的所有步骤。
要了解 Databricks Feature Store 的当前限制和其他可用的管理选项,请参考 docs.databricks.com/en/machine-learning/feature-store/troubleshooting-and-limitations.html
。
总结
在本章中,我们更深入地了解了特征库、它们解决的问题,以及在 Databricks 环境中实现特征库的详细过程。我们还进行了一个练习,注册了我们的第一个特征表。这将使我们能够利用特征表创建我们的第一个 ML 模型,正如我们在 MLFlow 章节中所讨论的。
接下来,我们将详细讲解 MLFlow。
进一步阅读
-
Databricks, Git 集成的 Repos:
docs.databricks.com/repos.html#repos-for-git-integration
-
你可以在这里了解更多关于支持的 RDBMS 信息:
docs.databricks.com/applications/machine-learning/feature-store/concepts.html#online-store
-
你可以在这里了解更多关于如何将特征表与训练 DataFrame 合并的信息:
docs.databricks.com/applications/machine-learning/feature-store/feature-tables.html#create-a-trainingset-when-lookup-keys-do-not-match-the-primary-keys
-
Apache Spark, Apache Arrow 在 PySpark 中的应用:
spark.apache.org/docs/latest/api/python/user_guide/sql/arrow_pandas.html
-
Databricks, 将 PySpark DataFrames 转换为 pandas DataFrames:(
docs.databricks.com/spark/latest/spark-sql/spark-pandas.html#convert-pyspark-dataframes-to-and-from-pandas-dataframes
)
第四章:理解 Databricks 上的 MLflow 组件
在上一章中,我们学习了特征存储,了解了它解决的问题,以及 Databricks 如何提供内建的特征存储作为 Databricks 机器学习 (ML) 工作区的一部分,我们可以使用它来注册我们的特征表。
在本章中,我们将深入探讨如何管理我们的模型训练、跟踪和实验。在软件工程师的世界里,代码开发和生产化有既定的最佳实践;然而,在 ML 工程/数据科学领域,这样的最佳实践并不普遍采用。在与许多 Databricks 客户合作时,我观察到每个数据科学团队都有自己管理项目的方式。这正是 MLflow 进场的地方。
MLflow 是一个由 Databricks 工程师开发的 umbrella 项目,旨在为 Databricks 平台提供一个标准化的 ML 生命周期管理工具。截至 2023 年 9 月,它已成为一个开源项目,日均下载量超过 50 万次,并得到了广泛的行业和社区支持。MLflow 提供了管理端到端 ML 项目生命周期的功能,其中一些功能仅在 Databricks 上可用。
在本章中,我们将讨论以下主题:
-
MLflow 概述
-
MLflow 跟踪
-
MLflow 项目
-
MLflow 模型
-
MLflow 模型注册表
-
示例代码展示了如何在 Databricks 中跟踪 ML 模型训练
这些组件在标准化和简化 ML 项目的生命周期中发挥着至关重要的作用。当我们在 Databricks 中使用 MLflow 时,某些 MLflow 功能比其他功能更有用。我们将在本章中指出最有用的功能。
技术要求
本书的所有代码都可以在 GitHub 仓库中找到:github.com/PacktPublishing/Practical-Machine-Learning-on-Databricks
,并且是自包含的。要执行这些笔记本,你可以直接使用 repos 将代码仓库导入到你的 Databricks 工作区。我们在之前的章节中讨论过 repos。
本章还假设你对 Apache Spark 中的用户定义函数有初步的了解。你可以在这里阅读更多关于它们的信息:docs.databricks.com/en/udf/index.html
。
MLflow 概述
ML 生命周期很复杂。它从将原始数据以原始格式从各种批处理和流处理来源导入数据/Delta lake 开始。数据工程师使用 Apache Spark 等工具,结合 Python、R、SQL 或 Scala 创建数据管道,以可扩展、高效和具成本效益的方式处理大量数据。
数据科学家随后利用数据湖中的各种精心策划的数据集生成特征表来训练他们的 ML 模型。数据科学家更喜欢使用 Python 和 R 等编程语言进行特征工程,使用 scikit-learn、pandas、NumPy、PyTorch 或其他流行的 ML 或深度学习库进行模型训练和调优。
一旦模型训练完成,它们需要以表述性状态转移(REST)应用程序编程接口(API)的形式进行实时推理,或者以用户定义函数(UDF)的形式在 Apache Spark 上进行批处理和流式推理。我们还需要对部署的模型应用监控和治理。如果模型性能或数据发生漂移,我们可能需要重新训练并重新部署模型。
这个过程是迭代的,并给希望开始进行 ML 项目的组织带来了许多开发挑战:
-
为数据科学家提供稳定的工作环境需要管理大量的软件工具。许多库需要手动安装和配置。
-
跟踪和重现 ML 实验的结果也是一大挑战。
-
管理服务和治理,尤其是将模型生产化,是一项困难的任务。
-
随着数据量的增加,模型训练的规模化是一大挑战。
MLflow 及其组件为每个挑战提供了解决方案。在 Databricks 环境中,MLflow 与工作区组件(如笔记本、特征存储和 AutoML)集成。这种集成为数据科学家和 ML 工程师提供了无缝体验,使他们能够专注于生产力,而无需处理自己安装和管理 MLflow 的操作开销:
图 4.1 – MLflow 的各个组件
MLflow 由四个软件组件组成:
-
MLflow 跟踪
-
MLflow 项目
-
MLflow 模型
-
MLflow 模型注册表
在 Databricks 中,除了 MLflow 项目外,所有这些组件都已集成、完全管理并作为 Databricks 工作区的一部分提供服务。由于我们的主要关注点是与 Databricks 无缝集成的 MLflow 特性,我们不会深入探讨 MLflow 项目。放心,使用 Databricks 时,这不会影响你的 ML 项目工作流程。Databricks ML 工作区还提供了高可用性、自动更新和对所有集成的 MLflow 组件的访问控制。
让我们详细了解一下这些组件。
MLflow 跟踪
MLflow 跟踪允许您跟踪机器学习模型的训练过程。它还提高了模型训练过程的可观察性。MLflow 跟踪功能使您能够记录生成的度量、工件和模型本身,作为模型训练过程的一部分。MLflow 跟踪还在 Databricks 环境中跟踪模型的谱系。在 Databricks 中,我们可以看到负责生成模型的笔记本的确切版本,作为源代码进行列出。
MLflow 还提供了 自动日志记录(autolog)功能,能够在执行模型训练时自动记录许多度量、参数和工件。我们还可以将自己的一组度量和工件添加到日志中。
使用 MLflow 跟踪,我们可以按时间顺序跟踪模型训练。某些术语是 MLflow 跟踪特有的。我们来看看它们:
-
实验:为商业问题训练和调优机器学习模型是一个实验。默认情况下,Databricks 中的每个 Python 笔记本都有一个相同名称的实验,这被称为笔记本作用域实验。您可以通过 MLflow API 轻松更改和设置实验名称。像这样定义实验将创建一个工作区作用域的 MLflow 实验,该实验现在可以在您的工作区中看到。自定义 MLflow 实验名称在机器学习工作流程中提供了重要的优势——例如,通过帮助您对实验进行分类和区分,它提高了组织的清晰度,起到了文档作用,促进了沟通与协作。自定义名称有助于版本控制和跟踪实验的演变,这对于比较性能或回顾过去的配置特别有用。此外,它们简化了通过 MLflow 用户界面或编程查询访问特定实验的过程,最终有助于更高效、更有效的机器学习项目管理。我们将在示例代码中使用自定义实验名称。
-
运行:我们可以在每个实验下记录多个使用不同超参数训练的模型。每个在实验下记录的机器学习模型训练的独特组合称为一次运行。附带的 MLflow 跟踪用户界面允许我们对比不同的运行并找到最佳模型。
-
Metrics: 每个运行将会有关键的离线指标,我们在训练模型时希望记录这些指标。与在线指标不同,后者是在模型与实时数据和用户交互时实时计算的,离线指标是使用在模型部署之前收集的固定数据集进行回顾性计算的。这些指标在模型开发和测试阶段至关重要,用于评估模型在未见数据上的泛化能力,并指导模型的优化。离线指标的常见示例包括准确率、精确度、召回率、F1 分数、均方误差(MSE)和接收者操作特征曲线下面积(AUC-ROC),等等。它们为模型的性能提供见解,并可以指导超参数调整、特征工程和模型选择,以提高总体预测准确性和效果。
-
Artifacts: MLflow 的 artifacts 在 MLflow 的实验跟踪系统中发挥着关键作用,通过便捷地存储和版本管理与 ML 实验相关的附加文件和数据。这些多功能 artifacts 可以涵盖各种资源,包括 ML 模型文件、数据集、配置文件、数据可视化(例如绘图)、文档(例如 README 和 Jupyter 笔记本)、自定义脚本,甚至是总结实验结果的报告。重要的是,artifacts 会随着实验运行进行版本控制,确保随时间的精确追踪变化。它们支持远程存储解决方案,并可通过 MLflow 的 API 进行编程访问。这种全面的方法增强了 ML 项目中的可重现性、组织性和协作性,使得能够准确重现实验并访问所有相关资源成为可能。
-
Parameters: Parameters 是与 ML 实验运行相关联的用户定义的配置设置或超参数。它们通过记录每个运行中使用的具体配置设置,对实验进行跟踪、比较和重现起着至关重要的作用。这使得能够轻松可视化和分析参数值如何影响实验结果,从而更简单地识别最佳配置并有效管理实验。
-
Tags: Tags 是用户定义或自动生成的元数据标签,可以附加到 ML 实验运行中。它们用于为运行提供上下文、分类和组织,有助于搜索、过滤和分析实验。Tags 有助于记录和区分不同的运行,从而更轻松地理解和管理 ML 项目,并可以用于自定义工作流集成或自动化。
接下来,我们将了解 MLflow 的关键组件之一,称为 MLflow Models。
MLflow Models
MLflow Models 是一种标准的 ML 模型包装格式。它在数据科学家创建的 ML 模型之上提供了标准化的抽象。每个 MLflow 模型本质上是一个包含根目录中的 MLmodel
文件的目录,该文件可以定义模型的多个 flavor。
Flavor 代表了一个基本概念,它通过为部署工具提供标准化的方法来理解和与 ML 模型交互,从而增强了 MLflow 模型的能力。这一创新消除了每个部署工具需要与每个 ML 库单独集成的需求。MLflow 引入了几个“标准”flavor,内置的部署工具普遍支持这些标准。例如,“Python 函数”flavor 描述了如何将模型作为 Python 函数执行。然而,flavor 的多样性不仅限于这些标准。库有灵活性来定义并使用自己的 flavor。例如,MLflow 的 mlflow.sklearn
库允许你将模型加载为 scikit-learn 管道对象,适用于在 scikit-learn 代码中使用,或者作为通用 Python 函数,满足需要应用模型的工具,比如使用 -t sagemaker
选项将模型部署到 Amazon SageMaker 上的 MLflow 部署工具。因此,flavor 作为 ML 库和部署工具之间的桥梁,提升了互操作性和易用性。
你可以使用 mlflow.<model-flavor>.log_mode``l
方法从实验中的一次运行注册一个 MLflow 模型。该方法将基础 ML 模型序列化为特定格式,并将其持久化到底层存储中。
查看官方文档,了解 MLflow Models 支持的完整 ML 库列表:www.mlflow.org/docs/latest/models.html#built-in-model-flavors
。如果你有一些已使用任何 Python ML 库开发的现有模型,MLflow 提供了一种通过 mlflow.pyfunc
模块创建自定义模型的方法。
还会记录其他文件,如 conda.yaml
和 requirements.txt
,这些文件包含库的依赖关系,用于在需要时重建运行时环境。
ML 模型 YAML 文件包含以下属性:
-
time_created
:以 UTC ISO 8601 格式表示的日期和时间,描述模型创建的时间。 -
flavors
:定义了下游应用程序如何使用该模型。 -
run_id
:表示 MLflow 运行的唯一标识符;该模型是通过 B 记录的。 -
signature
:以 JSON 格式表示的模型签名。该签名定义了 ML 模型的输入和输出数据的预期格式。它是通过代表有效输入和输出示例的数据集自动推断出来的,例如训练数据集和模型预测。 -
input_example
:这是如果在训练模型时提供示例记录作为输入时使用的。
MLflow 模型 API 提供了一种名为mlflow.evaluate()
的方法,它可以自动在评估数据集上评估我们训练的模型,并记录必要的度量指标,例如准确率、R2 和 SHAP 特征重要性,具体取决于我们试图解决的是什么问题。你还可以创建自定义度量并将它们作为参数传递给mlflow.evaluate(custom_metrics=[<your custom metric>])
。如果你想了解更多,进一步阅读 部分已提供相关链接。
MLflow 模型还提供 API,用于将打包的 ML 模型部署为 REST 端点进行实时推理,作为可以执行批量和流式推理的 Python 函数,或作为 Docker 容器,随后可以部署到 Kubernetes、Azure ML 或 AWS SageMaker。MLflow API 提供了诸如mlflow.models.build_docker
这样的便捷方法来构建和配置 Docker 镜像。你可以在这里阅读有关各种可用方法的更多信息:www.mlflow.org/docs/latest/python_api/mlflow.models.html?highlight=docker#mlflow.models.build_docker
。我们将在第七章,模型 部署方法 中探讨与 MLflow 集成的 Databricks 的各种部署选项。
现在,让我们看看列表中的下一个功能:MLflow 模型注册表。
MLflow 模型注册表
MLflow 模型注册表是一个工具,用于以集中方式协作管理整个组织中所有 MLflow 模型的生命周期。在 Databricks 中,集成的模型注册表提供了对谁可以将模型从一个阶段转换到另一个阶段的精细访问控制。
MLflow 模型注册表允许在特定阶段有多个版本的模型。它支持通过编程方式或人工干预部署模型,在各个阶段(如预生产、生产和归档状态)之间进行最佳模型的转换。选择哪种策略进行模型部署取决于使用案例以及团队在自动化整个 ML 模型升级和测试过程方面的舒适度。我们将在第六章,模型版本管理 和 Webhooks 中深入探讨这一点。
模型注册表还会记录模型描述、血统信息以及从一个阶段到另一个阶段的推广活动,提供完整的可追溯性。
我们将在第六章,模型版本管理 和 Webhooks 中更详细地探讨模型注册表功能。
下图总结了各个 MLflow 组件之间的交互:
图 4.2 – 各个 MLflow 组件如何相互交互
你可以灵活选择自己喜欢的 Python ML 库来进行模型训练,同时 MLflow Tracking 服务器会认真记录指标、标签和工件,并将你的模型打包成 MLflow Models 格式。一旦你完善了一个候选模型并准备好将其集成到模型注册表中,注册过程非常简单。模型注册表不仅提供 API,还提供治理机制,确保模型在各阶段之间平稳过渡。此外,MLflow 模型注册表引入了 webhooks,能够在特定用户操作时触发自动通知;我们将在第六章,模型版本控制与 Webhooks 中深入探讨这一点。最终,下游应用可以利用 API 从注册表中获取最新的模型,并将其以各种形式部署,包括 Python 函数、Docker 容器或其他支持批处理、流处理和实时使用场景的部署选项。
你可以通过使用到目前为止讨论过的功能,独立管理你的 ML 项目生命周期,即使不使用 Databricks Feature Store。然而,在 ML 项目中使用 Feature Store 提供了许多优势,包括集中化的数据管理,便于访问和一致性,跨项目的特征重用,版本控制以确保可重现性,数据质量检查,协作团队合作,扩展性以应对日益复杂的数据,实时特征服务,模型监控集成,合规性支持,以及显著的时间和成本节约。简而言之,Feature Store 通过提供结构化和高效的数据管理和特征处理方法,提升了 ML 工作流的效率和效果。
让我们来看一个端到端的代码示例,展示在 Databricks 环境中训练 ML 模型的整个流程,并利用集成的 MLflow 所有功能。
示例代码展示了如何在 Databricks 中跟踪 ML 模型训练
在继续之前,确保你已经克隆了与本书配套的代码库,正如在第三章中所述。此外,请验证你是否已经执行了与第三章相关的笔记本。这些准备步骤对于全面参与此处提供的内容和练习至关重要:
- 转到
第四章
,并点击mlflow-without-featurestore
笔记本:
图 4.3 – 本章配套的代码
确保你的集群已经启动并运行,并且集群已附加到此笔记本,正如你在第三章中所做的,使用 Feature Store。
-
Cmd 3
展示了如何使用笔记本范围的库。这些库可以通过%pip
魔法命令进行安装。最佳实践是将%pip
命令保留在笔记本的最顶部单元格中,因为它会重启 Python 解释器。我们这里只是升级了scikit-learn
库的版本:%pip install -U scikit-learn
-
在
Cmd 5
和Cmd 6
中,我们只是定义了一些常量值,用于跟踪我们的 ML 模型训练。将USER_EMAIL
值更改为您用于登录 Databricks 工作区的电子邮件。在此笔记本中,我们不会使用 Feature Store API;但是,每个特征表都存储为 Delta 表,可以像常规 Hive 表一样读取:from databricks.feature_store import FeatureStoreClientfrom databricks.feature_store import FeatureLookupimport typingfrom sklearn import metricsfrom sklearn.ensemble import RandomForestClassifierfrom sklearn.model_selection import train_test_splitimport mlflowimport pandas as pd# Name of experiment where we will track all the different model training runs.EXPERIMENT_NAME = "Bank_Customer_Churn_Analysis"# Name of the modelMODEL_NAME = "random_forest_classifier"# This is the name for the entry in model registryMODEL_REGISTRY_NAME = "Bank_Customer_Churn"# The email you use to authenticate in the Databricks workspaceUSER_EMAIL = "<your email>"# Location where the MLflow experiment will be listed in user workspaceEXPERIMENT_NAME = f"/Users/{USER_EMAIL}/{EXPERIMENT_NAME}"# we have all the features backed into a Delta table so we will read directlyFEATURE_TABLE = "bank_churn_analysis.bank_customer_features"
-
为了使用 Mlflow,我们需要导入
mlflow
包。mlflow.setExperiment(…)
创建一个命名实验,以跟踪我们将在此笔记本中执行的所有 MLflow 运行。执行此代码后,您应该能够在您的工作区目录中看到一个新类型的实体,其中EXPERIMENT_NAME
指向的内容。正如前面提到的,这会创建一个工作区范围的实验:# set experiment namemlflow.set_experiment(EXPERIMENT_NAME)
图 4.4 – 在工作区中创建的新实验
-
调用
mlflow.start_run()
将在列出的实验下启动一个运行。其余代码只是训练一个 scikit-learn 模型。只需几行代码,我们便开始使用 MLflow Tracking 的功能:with mlflow.start_run(): TEST_SIZE = 0.20 # Now we will read the data directly from the feature table training_df = spark.table(FEATURE_TABLE) # convert the dataset to pandas so that we can fit sklearn RandomForestClassifier on it train_df = training_df.toPandas() # The train_df represents the input dataframe that has all the feature columns along with the new raw input in the form of training_df. X = train_df.drop(['Exited'], axis=1) y = train_df['Exited'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=54, stratify=y) # here we will are not doing any hyperparameter tuning however, in future we will see how to perform hyperparameter tuning in scalable manner on Databricks. model = RandomForestClassifier(n_estimators=100).fit(X_train, y_train) signature = mlflow.models.signature.infer_signature(X_train, model.predict(X_train)) predictions = model.predict(X_test) fpr, tpr, _ = metrics.roc_curve(y_test, predictions, pos_label=1) auc = metrics.auc(fpr, tpr) accuracy = metrics.accuracy_score(y_test, predictions) # get the calculated feature importances. importances = dict(zip(model.feature_names_in_, model.feature_importances_)) # log artifact mlflow.log_dict(importances, "feature_importances.json") # log metrics mlflow.log_metric("auc", auc) mlflow.log_metric("accuracy", accuracy) # log parameters mlflow.log_param("split_size", TEST_SIZE) mlflow.log_params(model.get_params()) # set tag mlflow.set_tag(MODEL_NAME, "mlflow demo") # log the model itself in mlflow tracking server mlflow.sklearn.log_model(model, MODEL_NAME, signature=signature, input_example=X_train.iloc[:4, :])
-
以下代码利用 MLflow Tracking 服务器记录工件和超参数值,同时将
tag
设置为正在记录到 MLflow Tracking 服务器的sklearn
模型:mlflow.log_dict(importances, "feature_importances.json") # log metrics mlflow.log_metric("auc", auc) mlflow.log_metric("accuracy", accuracy) # log parameters mlflow.log_param("split_size", TEST_SIZE) mlflow.log_params(model.get_params()) # set tag mlflow.set_tag(MODEL_NAME, "mlflow demo") # log the model itself in mlflow tracking server mlflow.sklearn.log_model(model, MODEL_NAME, signature=signature, input_example=X_train.iloc[:4, :])
一旦我们完成执行此单元格中的代码,我们将能够在实验下看到该运行及其所有工件、参数和超参数:
图 4.5 – 实验下列出的运行
- 您可以通过点击快捷方式图标,查看 Tracking UI 中每次运行的详情:
图 4.6 – 访问集成 MLflow Tracking UI 的快捷方式
Tracking UI 以更多细节展示每次运行的信息。除了序列化模型,您还可以访问记录的工件、指标、超参数、模型签名,或者如果您在运行时记录了它们,还可以查看模型期望的输入样本。在顶部,您可以看到此运行所跟踪的实验路径。每个运行都有一个唯一的 ID,也会在顶部显示。跟踪服务器提供了溯源功能,并将此模型运行与执行该运行的笔记本的确切版本链接起来:
图 4.7 – 运行详情在 Tracking UI 中
- 点击顶部的实验路径,将带你进入实验视图,在这里,如果你执行了多个运行,你可以选择并比较不同的运行结果,以便找到最佳模型或比较最佳的超参数组合:
图 4.8 – 与我们的实验相关的所有运行
现在,让我们总结一下本章内容。
总结
本章我们介绍了 MLflow 的各个组件以及它们如何协同工作,使得端到端的机器学习项目生命周期管理变得简单。我们学习了 MLflow Tracking、Projects、Models 和 Model Registry。
本章介绍了 MLFlow 的一些关键组件及其用途。理解这些概念对于在 Databricks 环境中有效管理端到端的机器学习项目至关重要。
在下一章中,我们将详细介绍 Databricks 的 AutoML 功能,以及如何利用它们为机器学习项目创建基线模型。
第五章:使用 Databricks AutoML 创建基准模型
在上一章中,我们理解了MLflow及其所有组件。运行第四章的笔记本《在 Databricks 上理解 MLflow 组件》后,你可能已经意识到,在 Databricks 中使用集成的 MLflow 跟踪服务器来开始跟踪你的机器学习模型训练是多么简单。在本章中,我们将介绍另一个新的独特功能——Databricks的AutoML。
Databricks AutoML,像 Databricks 工作区中的其他所有功能一样,完全与 MLflow 功能和 Feature Store 集成。
在编写本书时,Databricks AutoML 支持分类、回归和预测的使用案例,采用的是传统的机器学习算法,而非深度学习。你可以在本章第二部分看到支持的算法列表。
你可以使用 Databricks 的 Hive 元存储中注册的表、特征表,甚至通过 Databricks 中的导入数据功能上传新的文件来使用 AutoML。你可以通过点击进一步阅读部分的链接了解更多信息。
本章将涵盖以下内容:
-
理解 AutoML 的需求
-
理解 Databricks 中的 AutoML
-
在我们的流失预测数据集上运行 AutoML
-
当前的限制
让我们来了解本章的技术要求。
技术要求
要通过本章内容,我们需要满足以下要求:
- 我们需要先执行涉及将 CSV 文件中的原始数据导入 Delta 表,并随后注册新的特征表的第三章的笔记本。
理解 AutoML 的需求
如果你从未使用过任何 AutoML 框架,可能会想知道什么是 AutoML,以及它何时以及如何能发挥作用。
AutoML 通过自动化各种任务简化了机器学习模型开发过程。它会自动生成针对特定数据集的基准模型,并提供预配置的笔记本来启动你的项目。这对于各个水平的数据科学家都特别有吸引力,因为它能节省模型开发初期的宝贵时间。与其从头开始手动构建模型,不如借助 AutoML 快速高效地获取基准模型,这使它成为初学者和经验丰富的数据科学家都值得使用的工具。
AutoML 不仅让公民数据科学家和业务领域专家可以接触到机器学习。虽然 AutoML 无疑是一个强大的工具,但它也面临着显著的限制。一个明显的挑战是它固有的黑盒特性,这使得很难,有时甚至不可能,解读哪些超参数和算法对于特定问题最有效。这种不透明性在实现模型可解释性时构成了一个实质性的障碍。
此外,许多市场上可用的 AutoML 工具未能支持机器学习生命周期中的关键组件,包括将模型投入生产使用这一至关重要的步骤。这一缺陷可能会妨碍机器学习解决方案与实际应用的无缝集成。
需要注意的是,AutoML 并不会替代数据科学家的角色。虽然它简化了模型开发的某些方面,但熟练的数据科学家的专业知识和见解仍然是确保机器学习项目成功的不可或缺的因素。
这就是 Databricks AutoML 实际上提供的最大好处之一。让我们更深入地了解 Databricks 中的 AutoML,看看你如何在模型开发过程中使用它。
了解 Databricks 中的 AutoML
Databricks AutoML 使用透明盒子方法进行 AutoML。当你通过 UI 或支持的 Python API 使用 Databricks AutoML 时,它会将每一个模型和超参数组合(试验)作为 MLflow 运行进行日志记录,并生成对应每个模型试验的 Python 笔记本和源代码。所有这些模型试验的结果都会被记录到 MLflow 跟踪服务器中。每一个试验都可以进行比较和重现。由于你可以访问源代码,数据科学家可以在修改代码后轻松重新运行某个试验。我们将在后面的例子中详细讲解这一点。
Databricks AutoML 还会准备训练数据集,然后在 Databricks 集群上执行模型训练和超参数调优。这里需要注意的一点是,Databricks AutoML 会将超参数调优试验分布到整个集群。一个试验是与模型相关的超参数的唯一配置。如果你的数据集很大,所有训练数据集应该适应一个单独的执行器,因为 Databricks AutoML 会自动对你的数据集进行抽样。
在编写本书时,Databricks AutoML 支持以下算法:
机器学习问题 | 支持的算法 |
---|---|
分类 |
-
Scikit-learn 模型:
-
决策树
-
随机森林
-
逻辑回归
-
-
XGBoost
-
LightGBM
|
回归 |
---|
-
Scikit-learn 模型:
-
使用随机梯度下降的线性回归
-
决策树
-
随机森林
-
-
XGBoost
-
LightGBM
|
预测 |
---|
-
Prophet
-
Auto ARIMA
|
表 5.1 – Databricks AutoML 支持的算法
让我们更详细地了解 Databricks AutoML 提供的一些关键功能。
大数据集的采样
采样是根据加载并训练模型所需的内存估算来进行的。在 ML Runtime 10.5 之前,数据采样不依赖于 VM 类型或执行器运行的内存量。在 ML Runtime 11.0 及更高版本中,如果节点是计算优化的并具有更大的内存,采样机制将增加采样比例和大小。
默认情况下,在 Databricks 中,每个执行器被配置为执行与可用 CPU 核心数量相同的试验次数。此外,执行器的可用内存会在这些试验之间均匀分配。然而,您可以通过调整 spark.task.cpus
配置参数来灵活修改此行为。
spark.task.cpus
的默认设置为 1
,这意味着每个执行器将并行执行与其 CPU 核心数量相同的试验。如果您将此值更改为与执行器上可用的 CPU 核心数量相匹配,将会导致不同的行为。在这种情况下,每次只会在执行器上执行一个试验,但该试验将能够访问执行器的全部内存容量。如果您希望为每个试验提供更多资源,这个设置会非常有用。此举也会增加采样数据集的大小。AutoML 使用 PySparks 的 sampleBy
方法(spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrameStatFunctions.sampleBy.html
)进行分类问题的分层采样。
对于回归问题,AutoML 在需要采样时使用 sample
方法(spark.apache.org/docs/latest/api/python/reference/api/pyspark.sql.DataFrame.sample.html
)。
采样不适用于 预测问题。
不平衡数据检测
在 Databricks Runtime 11.2 ML 及更新版本中,当 AutoML 检测到分类用例的类别不平衡时,它会采取措施缓解训练数据集中的不平衡。通过对主类进行下采样和引入类别权重的组合,来实现这一目标。需要注意的是,这个平衡过程仅应用于训练数据集,不会影响测试和验证数据集。这种方法保证了模型性能是基于原始数据集及其真实类别分布来评估的。
为了解决不平衡的训练数据集问题,AutoML 会根据对特定类别应用的下采样程度,分配与类别权重成反比的类权重。例如,假设训练数据集中有 100 个样本,其中 95 个属于Class A
,5 个属于Class B
。AutoML 通过将Class A
下采样到 70 个样本来减少这种不平衡,比例约为 70:95,即约为 0.736。与此同时,Class B
的样本数保持为 5。为了确保最终模型得到正确的校准,并且保持与输入数据相同的概率分布,AutoML 通过此比例的倒数(约为 1:0.736,即 1.358)来调整Class A
的类权重。Class B
的权重保持为 1。这些类权重将在模型训练过程中作为参数使用,确保来自每个类别的样本得到适当的加权,从而帮助构建一个平衡且准确的模型。
数据拆分为训练集/验证集/测试集
在 Databricks Runtime 10.1 ML 及之后的版本中,您可以在执行分类和回归任务的数据拆分时指定一个时间列。当您指定这个时间列时,数据集将根据时间顺序划分为训练集、验证集和测试集。最早的时间段的数据点会分配到训练集,其次是验证集,最新的数据点则保留在测试集。
在 Databricks Runtime 10.1 ML 中,时间列必须是时间戳或整数数据类型。然而,从 Databricks Runtime 10.2 ML 开始,您还可以灵活选择字符串列作为时间列。这一增强功能为基于时间的数据拆分提供了更大的灵活性,从而有助于改进模型训练和评估。
增强语义类型检测
语义类型检测是一个强大的功能,它在 Databricks Runtime 9.1 LTS ML 及以后版本中引入,旨在通过提供对每列中数据类型的智能洞察,增强 AutoML 的能力。需要注意的是,语义类型检测不适用于预测问题或已指定自定义填充方法的列。
AutoML 会对列进行彻底分析,以确定它们的语义类型是否与表架构中指定的数据类型(Spark 或 pandas)不同。一旦发现不一致,AutoML 将根据检测到的语义类型采取具体的行动。然而,值得注意的是,这些检测可能并不总是 100%准确。以下是 AutoML 可以进行的关键调整:
-
带有日期或时间戳数据的字符串和整数列:这些列会被智能地识别为时间戳类型,从而更精确地处理时间信息
-
表示数值数据的字符串列:在适用的情况下,这些列会被转换为数值类型,确保可以无缝地进行数学运算
从 Databricks Runtime 10.1 ML 开始,AutoML 扩展了其功能,涵盖以下内容:
-
包含类别 ID 的数值列:这些列被识别为类别特征,有助于在处理类别数据时进行更准确的建模
-
包含英文文本的字符串列:这些列被识别为文本特征,增强了数据集中对文本数据的理解
在 Databricks Runtime 10.1 ML 及以后版本中,用户可以通过 Python 注解手动设置语义类型。以下代码示例演示了这种手动注解过程的语法:
metadata_dict = df.schema["<column-name>"].metadatametadata_dict["spark.contentAnnotation.semanticType"] = "<semantic-type>"
df = df.withMetadata("<column-name>", metadata_dict)
您可以手动分配的可用语义类型如下:
-
类别型:适用于包含诸如 ID 等值的列
-
数值型:适用于包含数值的列
-
DateTime:适用于包含时间戳值的列
-
文本:保留用于包含英文文本的字符串列
若要禁用特定列的语义类型检测,可以使用特殊的关键字注解 native。
Shapley 值(SHAP)用于模型可解释性
Shapley 值(SHAP)是一种基于博弈论的技术,用于估算每个特征在机器学习模型预测中的重要性。AutoML 回归和分类笔记本自带计算这些值的内置代码,使用 SHAP 包进行计算。然而,由于计算 SHAP 非常占用内存,因此默认情况下未启用。
若要在 AutoML 笔记本中启用并计算 SHAP,您需要将shap_enabled
设置为True
,然后重新运行笔记本。值得注意的是,如果数据集中包含DateTime
列,则在版本 11.1 及更早版本的 MLR 中将不会生成 SHAP 图。
特征存储集成
在 Databricks Runtime 版本 11.3 LTS ML 及后续版本中,特征存储中的特征表可用于增强分类和回归任务的基础数据集。从版本 12.2 LTS ML 开始,这一功能扩展到增强输入数据集,以支持一整套 AutoML 挑战,包括分类、回归和预测。
当前 AutoML 的状态存在某些限制。仅支持数据集中以下数据类型:
-
数值型(
ByteType
、ShortType
、IntegerType
、LongType
、FloatType
和DoubleType
) -
布尔值
-
字符串(类别或英文文本)
-
时间戳(TimestampType和DateType)
-
ArrayType[Numeric]
(Databricks Runtime 10.4 LTS ML 及更高版本) -
DecimalType
(Databricks Runtime 11.3 LTS ML 及更高版本)
您还需要确保源数据集中的所有列名都是唯一的。如果您使用 AutoML 进行时间序列预测,并且希望使用 Auto ARIMA,请确保时间序列输入数据集中的任何两点之间的间隔相同。默认情况下,AutoML 会自动用前一个值填充缺失的时间步。
让我们看一个 AutoML 的示例用例。
在我们的客户流失预测数据集上运行 AutoML
让我们来看一下如何使用 Databricks AutoML 来预测我们银行客户的流失率。
如果您执行了来自第三章的笔记本,利用功能存储,您将会在 Hive 元存储中看到原始数据作为 Delta 表。它的名称为 raw_data
。在第三章的代码中,我们从 Git 仓库读取了一个 CSV 文件,将其作为 Delta 表写入,并在我们的集成元存储中注册它。请查看您笔记本中的 cmd 15
。在您的环境中,数据集可能来自另一个数据管道,或通过 上传文件 功能直接上传到 Databricks 工作区。
要查看表格,您需要确保集群已启动并运行。
图 5.1 – 原始数据集的位置
让我们创建第一个 Databricks AutoML 实验。
重要提示
确保在执行下一步之前,您的集群已启动并运行,并且配置如下:
单节点或多节点
以单用户模式访问
Databricks 运行时版本设置为 13.3 LTS ML 或更高版本
工作节点类型/驱动程序类型 是至少有四个核心的任何虚拟机类型
集群上不应安装除 Databricks 运行时为机器学习预装的库之外的任何其他库。AutoML 不兼容在共享访问模式下运行的集群。
- 在左侧选项卡中,点击实验。
图 5.2 – 实验选项卡的位置
- 在此页面顶部,点击创建 AutoML 实验。这将引导您进入 AutoML 配置页面。
图 5.3 – 如何创建新的 AutoML 实验 (1)
- 作为替代方案,您可以点击新建,然后选择AutoML 实验。
图 5.4 – 创建 AutoML 实验的另一种方式
-
要开始,您需要输入以下基本信息:
-
对于该集群的目的:这是您希望 AutoML 运行的集群配置。您可以重用我们在第三章中为利用功能存储创建的集群,和在第四章中为理解 MLflow 组件创建的集群。
-
机器学习问题类型:回归、分类或预测。
-
数据集:包含所有特征和标签/目标列的数据集。
-
图 5.5 – 如何创建一个新的 AutoML 实验 (2)
- 预测目标:这对于当前的分类问题是特定的。当您选择用于运行 AutoML 的数据集时,系统会自动填充所有列,您可以选择目标列。
图 5.6 – 展示如何创建一个新的 AutoML 实验 (3)
-
实验名称:这是用于跟踪所有试验的名称。
-
可选地,您还可以选择在运行试验时需要从选定的表格中包含哪些特性。在我们的案例中,
RowNumber
、CustomerId
和Surname
对我们的分析没有任何帮助,因此我们将从选择中移除它们。
图 5.7 – 如何创建一个新的 AutoML 实验 (4)
可选地,您还可以选择如何处理数据集中的缺失值。
在 Databricks Runtime 10.4 LTS ML 及更高版本中,您可以定义处理 null
值的方法。在用户界面中,您可以通过表格 Schema 部分的 Impute with 下拉菜单选择您希望使用的填充技术。
值得注意的是,AutoML 会根据数据类型和相关列的内容自动选择合适的填充策略。
图 5.8 – 如何创建一个新的 AutoML 实验 (5)
就是这样!这就是您开始使用 Databricks 中的 Glassbox AutoML 所需要做的五件事。
还有一些高级配置,例如在选择最佳表现模型时,您希望优化哪些指标,或者您希望包含哪些支持的训练框架来运行试验:
-
评估指标作为运行的主要评分指标。
-
从 Databricks Runtime 10.3 ML 开始,您可以排除某些训练框架。默认情况下,AutoML 使用其算法下列出的框架。
-
停止条件是可定制的。默认设置如下:
-
对于预测实验,120 分钟后停止。
-
对于 Databricks Runtime 10.5 ML 及更早版本中的分类和回归实验,停止条件为 60 分钟或 200 次试验,以先到者为准。从 Databricks Runtime 11.0 ML 开始,试验次数不再作为停止条件。
-
-
从 Databricks Runtime 10.1 ML 开始,AutoML 为分类和回归任务引入了早停策略,如果验证指标停止改进,则会提前停止。
-
从 Databricks Runtime 10.1 ML 开始,您还可以选择用于分类和回归任务中时间序列数据拆分的时间列。
-
你可以在数据目录字段中指定一个 DBFS 位置来保存训练数据集。如果留空,数据集将作为 MLflow 产物保存。
图 5.9 – 如何创建一个新的 AutoML 实验 (6)
为了增强数据集的丰富性,你可以无缝地集成现有的特征表。只需滚动到页面底部并点击连接特征选项。这将带你进入一个配置面板,在那里你可以精确指定要与现有数据集合并的特征表,并建立一个或多个键来支撑这个合并过程,从而有效地链接数据集。
然而,需要注意的是,为了这个示例,我们将不会将特征存储表包含在合并操作中。此方法使你能够通过从选定的特征表中获取额外信息来增强数据集,从而提高其在分析或机器学习任务中的实用性,同时在这个练习中省略特征存储表。
现在我们只需要点击开始 AutoML:
-
我们的 AutoML 实验现在正在执行,并且当前状态在用户界面中可见。随着 AutoML 的进展,它会生成以下三个产物:
- 它生成一个详细的数据探索笔记本,包含源代码,旨在概述任何偏差或问题,例如缺失数据或零值。它会自动使用
pandas.profiling
包来完成此操作。你可以通过点击查看数据 探索笔记本来查看此笔记本。
- 它生成一个详细的数据探索笔记本,包含源代码,旨在概述任何偏差或问题,例如缺失数据或零值。它会自动使用
图 5.10 – 如何访问自动生成的数据探索分析笔记本
数据探索笔记本还显示了不同特征之间的相关性:
图 5.11 – 由数据探索分析笔记本生成的相关性图
- 你可以看到实验试验,里面包含了每次在我们的数据集上运行的源代码。源代码列在你的工作区下的用户目录中的一个名为
databricks_automl
的文件夹中。
图 5.12 – 各种笔记本的位置,包含与每次试验相关的代码
- 最佳模型的笔记本也会在所有试验执行完成后由 AutoML 自动生成。这个笔记本会引导你完成所有特征工程和训练 ML 模型的步骤。试验会在追踪服务器中自动记录。笔记本还包含特征转换的代码。
图 5.13 – 记录由 AutoMl 识别的最佳模型的笔记本位置
它还利用 SHAP(pypi.org/project/shap/
)记录特征重要性。
图 5.14 – 一个示例的 SHAP 值图,作为最佳模型笔记本的一部分自动生成
本笔记本还解释了如何最终利用已训练的模型,通过各种部署选项,我们将在稍后的第六章,模型版本控制 和 Webhook中进行讨论。
-
你可以通过 UI 比较不同的实验。
-
你也可以利用 Python API 启动 AutoML 进行分类、预测或回归。通过 Python API,你还可以以编程方式从 AutoML 实验中提取最佳模型并用于推理。
这是一个启动分类任务的示例代码:
databricks.automl.classify( dataset: Union[pyspark.DataFrame, pandas.DataFrame], *, target_col: str, data_dir: Optional[str] = None, exclude_columns: Optional[List[str]] = None, # <DBR> 10.3 ML and above exclude_frameworks: Optional[List[str]] = None, # <DBR> 10.3 ML and above experiment_dir: Optional[str] = None, # <DBR> 10.4 LTS ML and above imputers: Optional[Dict[str, Union[str, Dict[str, Any]]]] = None, # <DBR> 10.4 LTS ML and above max_trials: Optional[int] = None, # deprecated in <DBR> 10.3 ML primary_metric: str = "f1", time_col: Optional[str] = None, timeout_minutes: Optional[int] = None,) -> AutoMLSummary
你可以在docs.databricks.com/applications/machine-learning/automl.html#classification-and-regression
查看更多关于各种参数的信息。
摘要
在本章中,我们讨论了 AutoML 的重要性,以及它如何帮助数据科学家快速上手并高效解决手头的问题。然后我们介绍了 Databricks AutoML 的玻璃盒方法,这使得模型结果更易于解释,并能够自动捕获血缘关系。我们还学习了 Databricks AutoML 如何与 Databricks 工作区中的 MLflow 追踪服务器集成。
在接下来的章节中,我们将更详细地介绍如何使用 MLflow 模型注册表和 Webhooks 管理机器学习模型的生命周期。
深入阅读
这里有一些其他有用的链接:
-
Databricks,什么是 AutoML?:(
docs.databricks.com/applications/machine-learning/automl.html#databricks-automl
) -
Databricks,导入 数据:(
docs.databricks.com/data/data.html#import-data-1
)
第三部分:机器学习治理与部署
你将学习如何利用 MLFlow 模型注册表来管理模型版本,并从不同阶段过渡到生产环境,同时使用 webhook 设置警报和监控。
本节包含以下章节:
-
第六章,模型版本控制与 Webhooks
-
第七章,模型部署方法
-
第八章,使用 Databricks Jobs 自动化 ML 工作流
-
第九章,模型漂移检测与再训练
-
第十章,使用 CI/CD 自动化模型再训练与重新部署
第六章:模型版本控制和 Webhooks
在上一章,我们深入探讨了Databricks AutoML的功能,详细分析了其各个组件。我们全面了解了数据科学从业者如何利用透明的“玻璃盒”AutoML 的强大功能,顺利启动机器学习解决方案,特别是在应对复杂的商业挑战时。
此外,我们通过自动化选择候选模型来将 AutoML 投入实践,解决我们的银行客户流失预测分类问题。为了促进这一过程,我们将强大的 MLflow 功能无缝集成到我们的工作流程中。这一集成让我们能够细致地跟踪模型训练的各个方面,提供了关于模型性能的宝贵见解,并使我们能够做出数据驱动的决策。我们的旅程还将我们带到了 MLflow 跟踪服务器,在那里我们记录并监控了整个训练过程,确保我们的银行客户流失预测项目高效且精准地执行。
本章中,我们将探讨如何从MLflow 跟踪服务器获取模型,并利用集成的MLflow 模型注册表来管理模型生命周期的下一步操作。
我们将覆盖以下主题:
-
理解模型注册表的必要性
-
将候选模型注册到模型注册表并管理访问权限
-
使用模型注册表管理 ML 模型生命周期
-
深入了解Webhooks在模型注册表中的支持
技术要求
让我们来看看本章的技术要求:
-
所有前面的笔记本,已经按描述执行过
-
一个启用了 Webhooks 的 Slack 工作区,用于某个频道(
api.slack.com/messaging/webhooks
)
理解模型注册表的必要性
在传统的软件工程中,中央代码仓库的概念已经相当成熟。然而,在数据科学领域,集中式模型仓库的概念仍在发展之中。虽然不能说不存在中央模型仓库——实际上确实有其他工具和平台提供类似的功能——但模型管理中的挑战是独特的,往往更加复杂。
这正是 Databricks 集成的 MLflow 模型注册表的亮点,特别是在促进数据科学团队之间的协作方面。
模型注册表的主要功能包括:
-
集中式发现:模型注册表作为一个集中的中心,注册了来自各个数据科学团队的模型。每个注册的模型都有一个可追溯到原始运行和模型训练时使用的笔记本版本的血统,使团队之间的协作变得更加容易。
-
生命周期管理:Databricks 提供了 UI 和 API 选项来管理模型的生命周期,从而简化了将模型从一个阶段提升到另一个阶段的过程。
-
自动化测试与部署:模型注册表允许你将不同版本的模型部署到各个阶段。你还可以附加备注并以自动化的方式对这些模型进行测试,确保只有最强健的模型进入生产环境。
-
访问控制:强大的权限功能控制谁可以访问、修改或部署已注册的模型,从而确保只有授权人员能够与模型进行交互。
现在,让我们看看如何将模型注册到模型注册表。
将你的候选模型注册到模型注册表并管理访问权限
你可以使用 UI 将候选模型注册到集成的模型注册表,或者使用 MLflow 模型注册表 API。
让我们首先看看 UI 选项:
- 我们将首先导航到由我们的 AutoML 执行创建的 MLflow 实验。我们可以通过点击左侧导航栏中的实验标签来导航到此页面:
图 6.1 – 如何访问实验页面
- 接下来,我们从列表中选择我们的实验:
图 6.2 – AutoML 创建的集成 MLflow 跟踪服务器中列出的实验
- 现在,我们可以访问作为 AutoML 执行的一部分所执行的所有运行。在这里,我们可以在 UI 中对运行进行排序,获取最佳的 F1 分数:
图 6.3 – 根据 F1 分数排序的与 AutoML 实验相关的各种模型和运行
- 接下来,我们选择列表中的第一个选项。在我的情况下,这是基于 LightGBM 的
sklearn
模型:
图 6.4 – 如何查看和访问最佳运行的记录模型
- 现在我们将进入该特定模型的 MLflow 运行页面。这个页面对你来说一定很熟悉,因为当你向下滚动时,你会看到所有的工件、指标和超参数都作为我们的运行的一部分自动记录下来(我们在前面的章节中讲解过这部分内容):
图 6.5 – AutoML 为每个实验运行自动记录的不同工件
在右侧,你会看到一个标有注册模型的按钮:
图 6.6 – 如何将候选模型注册到模型注册表 1
- 如果您是第一次使用 MLflow 模型注册表,您可以选择
Churn Prediction Bank
。然后,点击注册:
图 6.7 – 如何将候选模型注册到模型注册表 2
此时,您的模型已在模型注册表中注册,并且如果访问模型页面,应该可以看到该模型。
- 您可以通过点击左侧导航栏中的模型图标来访问模型页面:
图 6.8 – 如何访问模型注册表
- 只需从列表中选择Churn Prediction Bank模型:
图 6.9 – 模型注册表中已注册的候选模型
这里有几个需要注意的事项如下:
-
最新版本显示为版本 1。这是因为我们在注册表中创建了一个新的模型条目。如果我们在步骤 9的下拉菜单中选择一个现有模型,那么版本将显示为版本 2,以此类推。
-
点击版本 1后,您将进入该版本模型的详细页面,并看到源运行列为lightgbm,这与生成我们最佳模型的运行相同。此外,输入和输出模式将自动从源运行中的模型签名继承。
您还可以在用户界面中为您的模型设置标签并添加描述:
图 6.10 – 已注册的候选模型版本详细信息
默认情况下,阶段设置为无。您可以通过内置的访问控制来管理谁有权限请求将模型从一个阶段转移到另一个阶段。
- 您可以通过点击我们在步骤 8中交互的页面上的权限标签,按用户或组级别设置权限。
图 6.11 – 如何为模型访问添加治理 1
默认情况下,工作区管理员和模型的原始创建者拥有可以 管理的权限:
图 6.12 – 如何为模型访问添加治理 2
您还可以指定按阶段授予对模型生命周期的访问权限或控制。在 Databricks MLflow 的模型注册表中,每个模型版本可以被分类到三个不同的生命周期阶段之一:暂存、生产或归档。值得注意的是,多个模型版本可以共存于同一生命周期阶段。这对于像 A/B 测试这样的场景非常有利,其中需要并行评估不同的模型版本。然而,这一特性可能给组织在管理和区分同一生命周期阶段内的多个模型时带来挑战。
为了解决这个问题,MLflow 提供了标签机制。可以为模型版本应用标签,以提供额外的元数据,便于在同一阶段内识别、过滤和管理模型。如果在同一阶段内有多个模型版本,默认情况下将加载最新版本的模型。然而,当同一阶段内存在多个版本时,明确指定要加载哪个模型版本是非常重要的,特别是在存在多个版本的情况下。在第七章《模型部署方法》中,我们将深入探讨如何有效地部署这些已过渡的模型。用户界面允许您修改模型版本的阶段,如下图所示。
图 6.13 – 模型阶段过渡的多种选项
- 点击请求过渡到,然后选择暂存。此操作将向模型所有者发送通知,告知我们已经请求对该模型进行审查并要求其过渡到暂存阶段。在我们的案例中,由于我们拥有该模型,所以我们会收到该通知。我们还可以在模型过渡请求中添加评论:
图 6.14 – 将模型过渡到暂存阶段
- 作为模型的所有者,我们可以查看所有关于该模型的评论,并有权选择批准、拒绝或取消请求。点击批准后,我们的模型将被过渡到暂存阶段:
图 6.15 – 文档历史记录及批准模型过渡请求的能力
通过用户界面执行的所有上述操作,也可以通过 MLflow Python API 来完成,当您想为模型训练和部署创建自动化工作流时。
现在让我们看看如何通过编程方式将模型注册到集成的模型注册表中,并将其过渡到暂存阶段。前往与第六章
关联的笔记本,并在 Databricks 工作区中打开它。
在第三个代码单元格中,我们通过编程方式检索最近修改的实验。目标是根据我们选择的评估指标,从这个实验中提取出表现最好的模型:
import mlflow# Initialize the Mlflow client
client = mlflow.tracking.MlflowClient()
# Fetch all available experiments
experiments = client.search_experiments()
# Sort the experiments by their last update time in descending order
sorted_experiments = sorted(experiments, key=lambda x: x.last_update_time, reverse=True)
# Retrieve the most recently updated experiment
latest_experiment = sorted_experiments[0]
# Output the name of the latest experiment
print(f"The most recently updated experiment is named '{latest_experiment.name}'.")
# Note: If you're specifically looking for the experiment related to AutoML for base model creation,
# ensure that 'latest_experiment' corresponds to that experiment.
在第五个单元格中,我们首先初始化一些参数,例如我们现有的用户名、experiment_name
(与我们的 AutoML 相关联的实验名称),以及 registry_model_name
(将在模型注册表中的模型名称)。在前面的部分,我们已经使用 UI 在注册表中注册了候选模型,注册名为 MlflowClient
库,该库来自 mlflow.tracking
包,用于访问基于与最佳模型运行关联的 run_id
的最佳模型:
# Initialize the Databricks utilities to programmatically fetch the usernameusername = dbutils.notebook.entry_point.getDbutils().notebook().getContext().userName().get()
# Retrieve the name of the latest experiment; assumed to have been set in earlier steps
experiment_name = latest_experiment.name
# Define the model name for the registry, specific to our use-case of Churn Prediction for a Bank
registry_model_name = "Churn Prediction Bank"
# Fetch the experiment details using its name
experiment_details = client.get_experiment_by_name(experiment_name)
# Search for runs within the experiment and sort them by validation F1 score in descending order
sorted_runs = mlflow.search_runs(experiment_details.experiment_id).sort_values("metrics.val_f1_score", ascending=False)
# Get the run ID of the best model based on the highest validation F1 score
best_run_id = sorted_runs.loc[0, "run_id"]
best_run_id
# Note: The variable `best_run_id` now contains the run ID of the best model in the specified experiment
要注册与最佳模型训练运行相关联的模型,我们需要提供模型 URI(在跟踪服务器中的模型路径),作为输入传递给 MLflow 注册表的 register_model
API。我们需要传递的另一个参数是我们希望从模型跟踪服务器中检索的新版本模型的名称。为了简化起见,我们将名称保持为与 UI 中定义的模型名称相同,因此新模型将作为 版本 2 注册到模型注册表中:
# Initialize the model's URI using the best run ID obtained from previous stepsmodel_uri = f"runs:/{best_run_id}/model"
# Register the model in Mlflow's model registry under the specified name
try:
model_details = mlflow.register_model(model_uri=model_uri, name=registry_model_name)
print(f"Successfully registered model '{registry_model_name}' with URI '{model_uri}'.")
except mlflow.exceptions.MlflowException as e:
print(f"Failed to register model '{registry_model_name}': {str(e)}")
model_details
你还可以使用 MLflowClient
对象来更新注册表中模型的描述或设置与模型相关的标签。在笔记本的 Command 9
中,我们演示了如何使用 MLflowClient
对象调用 update_registered_model
和 update_model_version
方法:
# Update the metadata of an already registered modeltry:
client.update_registered_model(
name=model_details.name,
description="This model predicts whether a bank customer will churn or not."
)
print(f"Successfully updated the description for the registered model '{model_details.name}'.")
except mlflow.exceptions.MlflowException as e:
print(f"Failed to update the registered model '{model_details.name}': {str(e)}")
# Update the metadata for a specific version of the model
try:
client.update_model_version(
name=model_details.name,
version=model_details.version,
description="This is a scikit-learn based model."
)
print(f"Successfully updated the description for version {model_details.version} of the model '{model_details.name}'.")
except mlflow.exceptions.MlflowException as e:
print(f"Failed to update version {model_details.version} of the model '{model_details.name}': {str(e)}")
在笔记本的 Command 11
中,我们演示了如何使用 MLflowClient
对象中的 transition_model_stage
方法,将最新的模型版本转换到 Staging
阶段。你也可以在将新模型转移到 Staging
阶段时归档早期的模型:
# Transition the model version to the 'Staging' stage in the model registrytry:
client.transition_model_version_stage(
name=model_details.name,
version=model_details.version,
stage="Staging",
archive_existing_versions=True # Archives any existing versions in the 'Staging' stage
)
print(f"Successfully transitioned version {model_details.version} of the model '{model_details.name}' to 'Staging'.")
except mlflow.exceptions.MlflowException as e:
print(f"Failed to transition version {model_details.version} of the model '{model_details.name}' to 'Staging': {str(e)}")
现在,让我们探索如何利用 MLflow 模型注册表提供的 webhook 事件来自动化通知。当与在 MLflow 注册表中注册的模型相关的特定事件发生时,这将提醒我们。
深入了解模型注册表中的 webhook 支持
Webhook 允许用户创建自定义回调,以便在 Web 应用程序之间启用通信。Webhook 使得系统在某些事件发生时,能够自动将数据推送到另一个系统。
举个例子,如果你想在检测到 MLflow 中的模型请求新转移时,自动在 Slack 上触发通知,或者当你在版本控制分支中进行新的代码提交时,自动触发新的模型构建,这种情况就适用。
MLflow Webhook 提供了功能,允许最终用户自动监听与模型注册表相关的任何事件,并触发相应的操作。这些 webhook 可以与消息系统(如 Slack)集成,用于发送通知或触发 CI/CD 流水线,自动测试和部署 ML 模型。
你可以使用 Python 客户端或 Databricks REST API 来使用 webhook。
MLflow 模型注册表支持两种不同类型的 webhook,具体取决于目标:
-
具有 HTTP 端点的 Webhook:当我们想要将触发事件发送到像 Slack 这样的 HTTP 端点时,使用此类型的 webhook。
-
Databricks 作业的 Webhooks:这些主要用于将触发事件发送到 Databricks 作业。这种类型的 webhook 对于在 CI/CD 过程中自动启动新推送到暂存或生产环境的模型的自动化测试特别有用。
以下图示总结了将模型注册到 MLflow 模型注册表的工作流,以及如何使用 MLflow webhooks 启动 Slack 通知和 Databricks 作业,以对新部署的模型应用标签/评论或自动化测试:
图 6.16 – 使用 webhooks 进行模型管理的典型工作流
注意
感谢 Databricks
一旦模型阶段转换请求被提交,HTTP webhook 可用于通知可以审查请求并批准它的用户/用户组。
您还可以为特定模型或为某个注册表中注册的所有模型设置 webhooks。
您可以在 docs.databricks.com/en/mlflow/model-registry-webhooks.html#webhook-events
阅读有关各种支持的 webhook 事件。
在本章提供的代码示例中,我们特别使用了以下两个事件:
-
MODEL_VERSION_CREATED
:为相关模型创建了一个新的模型版本 -
TRANSITION_REQUEST_CREATED
:用户请求将某个模型版本的阶段转换
为了演示如何通过 Slack 为模型转换建立自动警报,您必须首先获取一个 Slack webhook URL。以下步骤将指导您创建一个 Slack 应用程序,并随之设置一个入站 webhook。关于这一主题的详尽指南,请参阅官方的 Slack API 文档 api.slack.com/messaging/webhooks
。
如果您正在积极运行 Chapter 06
笔记本中的代码,确保在继续执行 Command 16
之前,您已经准备好 Slack webhook URL。
注意
这里需要记住的一点是,我们将要访问的用于创建新的注册表 webhook、删除 webhooks、列出 webhooks 等 REST 端点仅在 Databricks 上可用,而在开源的 MLflow 中不可用。您可以在 docs.databricks.com/dev-tools/api/latest/mlflow.html#operation/get-registered-model
阅读更多关于 Databricks REST API 规范的信息。
让我们继续查看位于 Chapter 06
文件夹中的笔记本。我们将深入探讨如何利用 webhooks 在模型注册表中当特定事件发生时,自动向 Slack 渠道发送通知。
-
在
Command 15
中,我们指定了一个代码块,提供了与 MLflow 的 REST API 进行交互的实用功能。它初始化了一个 MLflow 客户端并获取主机和令牌凭证用于身份验证。mlflow_call_endpoint
函数旨在使用GET
或其他 HTTP 方法向指定的 MLflow API 端点发出 HTTP 调用。它接受 API 端点、HTTP 方法和一个可选的 JSON 有效负载作为参数,并将返回一个以字典形式表示的 JSON 响应。该脚本还处理异常,如果 API 调用失败,将打印错误信息:from mlflow.utils.rest_utils import http_requestimport jsondef get_mlflow_client(): """Returns an initialized MLflowClient object.""" return mlflow.tracking.client.MlflowClient()def get_host_creds(client): """Fetches host and token credentials.""" return client._tracking_client.store.get_host_creds()def mlflow_call_endpoint(endpoint, method, body='{}'): """Calls an MLflow REST API endpoint. Parameters: endpoint (str): The endpoint to call. method (str): HTTP method ('GET' or other HTTP methods). body (str): JSON-formatted request payload. Returns: dict: JSON response as a dictionary. """ host_creds = get_host_creds(get_mlflow_client()) try: if method == 'GET': response = http_request( host_creds=host_creds, endpoint=f"/api/2.0/mlflow/{endpoint}", method=method, params=json.loads(body) ) else: response = http_request( host_creds=host_creds, endpoint=f"/api/2.0/mlflow/{endpoint}", method=method, json=json.loads(body) ) return response.json() except Exception as e: print(f"Failed to call MLflow endpoint '{endpoint}': {str(e)}") return Noneclient = get_mlflow_client()host_creds = get_host_creds(client)host = host_creds.hosttoken = host_creds.token
-
在
Command 16
中,将slack_webhook
变量的值分配给你 Slack 频道的 Webhook 链接:slack_webhook = "https://hooks.slack.com/services/?????????/??????????/???????????????????????"
-
执行
Command 17
和Command 18
。这将为我们为客户预测银行问题注册的新模型注册新 Webhook。当创建新的模型版本或对模型版本进行了转换请求时,我们将收到通知:import jsontrigger_for_slack = json.dumps({ "model_name": registry_model_name, "events": ["MODEL_VERSION_CREATED"], "description": "Triggered when a new model version is created.", "http_url_spec": { "url": slack_webhook }})mlflow_call_endpoint("registry-webhooks/create", method = "POST", body = trigger_for_slack)trigger_for_slack = json.dumps({ "model_name": registry_model_name, "events": ["TRANSITION_REQUEST_CREATED"], "description": "Triggered when a new transition request for a model has been made.", "http_url_spec": { "url": slack_webhook }})mlflow_call_endpoint("registry-webhooks/create", method = "POST", body = trigger_for_slack)
-
http_url_spec
参数是你提供 HTTP Webhook URL 的位置。 -
现在,在此之后,如果你返回到模型 UI 或请求将模型转换到新阶段,你将在 Slack 中收到通知:
图 6.17 – 使用 Slack Webhook 在 Slack 频道接收自动化通知
该笔记本还展示了其他 REST API 调用,这些调用可以帮助你管理 Webhooks。
我们刚刚看到一个如何使用 Webhook 处理 HTTP 端点的例子。同样,我们可以设置一个作业注册 Webhook。这可以用来触发你可能用于测试模型或重新训练模型版本的某些 Databricks 作业。
在工作注册 Webhook 中,你需要提供两个与 HTTP 注册 Webhook 不同的参数:job_spec
和workspace_url
。你可以在与模型注册中心不同的工作区中启动作业。如果你没有定义workspace_url
,则默认情况下,作业规范将用于触发与模型注册中心相同工作区中的 Databricks 作业。
总结
在本章中,我们介绍了如何利用 Databricks 模型注册中心来管理 ML 模型的版本控制和生命周期。我们还学习了如何使用 MLflow 模型注册中心来管理 ML 模型的版本,并在管理访问控制的同时,将模型从一个阶段转换到另一个阶段。接着,我们了解了如何使用 MLflow 支持的 Webhook 回调设置自动化 Slack 通知,以便跟踪模型注册中心中的模型变更。
在接下来的章节中,我们将介绍各种模型部署方法。
进一步阅读
以下是一些进一步帮助理解的链接:
-
Databricks,Databricks AutoML:
docs.databricks.com/applications/machine-learning/automl.html#databricks-automl
-
Databricks,作业注册 Webhook 示例 工作流:
docs.databricks.com/applications/mlflow/model-registry-webhooks.html#job-registry-webhook-example-workflow
-
Slack,使用传入的 Webhooks 发送消息:
api.slack.com/messaging/webhooks#enable_webhook
第七章:模型部署方法
在上一章中,我们了解了如何利用 Databricks MLflow 模型注册表来管理我们的机器学习模型版本和生命周期。我们还学习了如何使用集成的访问控制来管理对模型注册表中已注册模型的访问。我们还了解了如何使用模型注册表中可用的 Webhook 支持,触发自动的 Slack 通知或作业,以验证注册表中的已注册模型。
在本章中,我们将从模型注册表中获取已注册的模型,并了解如何使用 Databricks 中可用的各种模型部署选项进行部署。
我们将涵盖以下主题:
-
理解机器学习部署和范式
-
部署机器学习模型进行批处理和流处理推理
-
部署机器学习模型进行实时推理
-
将自定义 Python 库集成到 MLflow 模型中以进行 Databricks 部署
-
使用 MLflow 和模型服务部署自定义模型
-
将依赖项打包到 MLflow 模型中
让我们看看本章的技术要求。
技术要求
在深入本章之前,我们需要以下内容:
-
访问 Databricks 工作区
-
运行一个包含Databricks 机器学习运行时(Databricks Runtime ML)的集群,版本为 13 或更高
-
所有前面的笔记本,如上所述执行
-
基础的 Apache Spark 知识,包括 DataFrame 和 SparkUDF
让我们来看一下机器学习部署到底是什么。
理解机器学习部署和范式
数据科学与数据工程不同。数据科学更侧重于将商业问题转化为数据问题,并利用科学方法进行解决。我们开发数学模型,然后优化其性能。而数据工程师主要关注数据湖中数据的可靠性。他们更关注用于使数据管道可扩展和可维护的工具,同时确保符合服务水平 协议(SLA)。
当我们谈论机器学习部署时,我们希望弥合数据科学和数据工程之间的差距。
下图可视化了整个机器学习部署过程:
图 7.1 – 展示机器学习部署过程
在右侧,我们展示了数据科学的过程,这是一个非常互动和迭代的过程。我们理解商业问题,并发现可以为分析增值的数据集。然后,我们构建数据管道来处理数据并进行分析。我们开发我们的模型,链条继续。
该图的左侧展示了将软件开发领域的最佳实践与数据科学领域的整合。这大多是自动化的。一旦我们的候选模型准备就绪,我们会执行以下步骤:
-
首先,我们将其注册到模型注册表。
-
接下来,我们将模型与我们的应用程序集成。
-
接下来,我们将用我们的应用程序测试集成后的模型。
-
最后,我们将其部署到生产环境中,在那里我们监控模型的性能并加以改进。
其中一些过程可能看起来与 DevOps 非常相似,但DevOps和ModelOps之间存在一些关键的区别。
本质上,DevOps 结合了软件开发和 IT 运营,如持续集成(CI)、持续部署(CD)、更新或回滚功能以及推送补丁。
ModelOps 结合了 DevOps 的原则,如 CI/CD,并结合了机器学习领域的特定需求。它引入了持续训练和监控 ML 模型的需求。
持续训练是 ModelOps 中的一个重要方面。与传统软件不同,传统软件模块一旦部署后很少发生变化,ML 模型需要不断更新。随着新数据的涌入,模型必须定期重新训练,以确保其准确性和相关性。这意味着即使核心模型代码保持不变,模型本身也会随着数据环境的变化而进化。
ModelOps 中的持续监控涵盖了两个关键领域:模型性能监控和基础设施监控。模型性能监控涉及追踪模型在现实场景中的表现,包括准确率、精度、召回率等指标。另一方面,基础设施监控关注支持模型的计算基础设施的健康状况和性能。这种双重监控方法确保了模型和底层系统的最佳运行状态。
这种方法与传统软件工程有所不同,在传统软件工程中,一旦软件模块经过测试并部署到生产环境,它通常保持稳定,无需持续监控和适应。而在 ModelOps 中,数据的不断变化和维护模型性能的重要性使得持续训练和监控成为过程的核心部分。
在 MLOps 的初期,大多数公司使用 Java 和定制的内部工具来管理 ML 部署、持续训练和监控。然而,现在大多数工具和框架已经开源,并且我们已经看到 Python 成为了实施整个模型开发生命周期的事实标准。
让我们来看一下最常见的 ML 部署模式。大多数 ML 用例可以分为四类:
-
批量部署(可即时运行或按计划执行):
-
这些是最常见的部署方式,实施相对简单,且在成本和生产化工作量方面最为高效。
-
模型进行预测,并将预测结果存储在快速访问的数据仓库中,如 DynamoDB、Cassandra、Cosmos DB 或数据湖仓中的 Delta 表。这些存储解决方案因其高效的预测服务能力而被选择。然而,需要注意的是,这些选择是为具有低延迟检索要求的使用场景量身定制的,而批处理使用场景则可能有不同的考虑因素。此外,Databricks SQL 提供了一种无服务器的高性能数据仓储解决方案,它与数据湖仓无缝集成,简化了数据管理和分析,提高了利用预测模型的生产力和可靠性。值得一提的是,Delta 表还结合了写入优化,确保了高效的数据存储和处理。
-
-
流式部署(持续运行在数据上):
-
当你在推理开始之前无法访问整个数据集,并且需要在新数据到达时相对快速地处理它们时,这些部署变得至关重要。
-
Spark Structured Streaming 非常适合处理流数据。它还内置了排队机制,在处理大量图像数据时非常有用。
-
-
实时(REST 端点):
-
当使用场景需要模型作为应用的一部分进行近实时的请求和响应时,这些部署变得尤为重要。
-
在编写本书时,Databricks 提供了一项与其平台无缝集成的生产级模型服务。该服务利用无服务器计算的强大功能以实现最佳性能。尽管深入探讨各种部署架构的细节超出了本书的范围,但你可以在 Databricks 文档中访问有关此主题的详细信息(
docs.databricks.com/en/serverless-compute/index.html
)。另外,你还可以在 Databricks 上通过 Azure ML(利用 Azure Kubernetes 服务)、AWS Sagemaker 和 Google Vertex AI 等各种云服务,轻松地将你的机器学习模型部署为 REST 端点。机器学习模型被打包成容器镜像,然后与相应云提供商提供的托管服务进行注册。 -
你还可以使用自己的 Kubernetes 集群,使用相同的范式进行模型部署。
-
-
设备端(边缘):
- 这些是非常特定的使用场景,我们希望将模型部署到诸如 Raspberry Pi 或其他物联网设备上。我们将在本章中不涉及这些内容。
最佳实践是,初步考虑将批量部署作为你的主要机器学习部署范式。仅在彻底验证批量部署不足以满足你的特定用例时,才过渡到其他范式。请记住,实时机器学习部署系统的长期维护成本通常高于批量系统。
在选择最合适的机器学习部署范式时,考虑响应延迟要求同样至关重要:
-
批量部署:最适合那些推理响应时间预期为几小时到几天的场景:
- 用例推荐:对于那些不受时间限制的数据分析和报告任务,尤其是生成每月销售预测或风险评估,这种部署方法特别有用。
-
结构化流式部署:最适合那些需要在几分钟到一小时内对新数据进行推理的用例:
- 用例推荐:实时分析或欺诈检测系统通常会从这种部署类型中受益,这些系统需要持续分析数据流,但即时响应并不是关键。
-
近实时或 REST 端点部署:当预期延迟在几百毫秒到一分钟之间时,这些部署方式最为合适:
- 用例推荐:这种部署范式最适合应用于实时推荐系统或自动化客户服务机器人等需要较快响应但不要求立即反应的应用。
-
边缘部署:这些部署适用于那些要求小于 100 毫秒 SLA 的场景:
- 用例推荐:对于物联网(IoT)应用、自动驾驶车辆或任何需要闪电般决策能力的用例,这一点至关重要。
这些只是一些大致的指导原则。以下图表总结了我们在这里讨论的所有要点:
图 7.2 – 各种机器学习部署的响应延迟要求
现在,让我们来看一下使用 Databricks 时的各种部署选项。除了这里讨论的部署方法,一些开源项目可能会对你有兴趣,尤其是将模型作为 REST 服务进行部署。这些项目的链接可以在本章末尾的进一步阅读部分找到。
部署机器学习模型进行批量和流式推理
本节将介绍使用 Databricks 以批量和流式方式部署机器学习模型的示例。
在批量和流式推理部署中,我们使用模型进行预测,然后将预测结果存储在某个位置以供以后使用。预测结果的最终存储区域可以是一个具有低延迟读取访问的数据库、用于导出到其他系统的云存储(如 S3),甚至是一个可以被业务分析师轻松查询的 Delta 表。
在处理大量数据时,Spark 提供了一个高效的框架来处理和分析数据,这使得它成为了一个理想的候选框架来利用我们训练的机器学习模型。
注意
需要记住的一个重要提示是,我们可以使用任何非分布式的机器学习库来训练模型。只要它使用了 MLflow 的模型抽象,就可以利用 MLflow 模型注册表的所有好处,并且可以使用本章中呈现的代码。
我们应该始终考虑模型生成的结果的访问模式。根据我们存储预测结果的位置,我们可以进行以下优化:
-
分区可以加速数据读取,尤其是当你的数据以静态文件形式存储或保存在数据仓库中时。
-
在数据库中为相关查询构建索引,通常会提高性能。
让我们看一个如何在 Databricks 环境中执行批量和流式推理部署的示例。
在 Databricks 上进行批量推理
批量推理是最常见的模型部署方式。批量推理的意思是使用模型进行预测并将结果存储以供后续使用。
为此,我们将使用在 MLflow 的模型注册表中可用的模型。我们必须确保在此章节提供的笔记本中至少有一个模型版本处于 Staging 阶段,以便执行:
- 进入Models选项卡,选择Churn Prediction Bank已注册模型。应该会有一个版本处于Staging状态:
图 7.3 – 模型注册表中 Staging 阶段的已注册模型
-
打开与
Chapter-07
相关联的笔记本,名为Batch and Streaming。我们将简单地将模型从注册表加载为 Python 函数,如下所示的代码块:import mlflow# the name of the model in the registryregistry_model_name = "Churn Prediction Bank"# get the latest version of the model in staging and load it as a spark_udf.# MLflow easily produces a Spark user defined function (UDF). This bridges the gap between Python environments and applying models at scale using Spark.model = mlflow.pyfunc.spark_udf(spark, model_uri = f"models:/{registry_model_name}/staging")
-
该笔记本的其余部分读取与我们用于训练模型的相同
raw_data
,以 Spark DataFrame 的形式进行读取,然后在选择用于训练分类模型的列之后,使用 AutoML 进行训练:spark_df = spark.table("bank_churn_analysis.raw_Data")display(spark_df)exclude_colums = {'RowNumber', "CustomerId", "Surname", "Exited"}input_columns = [col for col in spark_df.columns if col not in exclude_colums]input_columns# passing non label columns to the model as inputprediction_df = spark_df.withColumn("prediction", model(*input_columns))display(prediction_df)
让我们看看如何利用相同的模型加载为 Spark UDF 进行流式推理部署。
本章不详细讨论 Spark 中的结构化流式处理,因为它本身是一个庞大的话题。《Spark: The Definitive Guide: Big Data Processing Made Simple》是一本深入学习 Apache Spark 和结构化流式处理的好书。流式 DataFrame 可以被看作是一个不断更新的无界表格,随着新数据的到来持续更新。在进一步阅读部分中,提供了关于结构化流式处理的更多资源链接,供你深入学习。
在 Databricks 上进行流式推理
让我们看一下示例代码,展示如何将上一节中使用的模型部署以进行流式推理:
-
在
Cmd 15
中,我们必须将来自 Delta 表的raw_data
定义为流式读取而非批量读取:# right now we are just defining a streaming data source but this statement will not execute until we call an Spark action. Another way to exclude the columns that are not needed is by dropping them from the DataFrame.raw_streaming_df = spark.readStream.format("delta").option("ignoreChanges", "true").table("bank_churn_analysis.raw_Data").drop(*("RowNumber", "CustomerId", "Surname", "Exited"))
剩余的流程将与批量推理类似。
-
一旦我们定义了我们的流式 Dataframe,我们调用在暂存环境中可用的模型注册表中加载的相同模型:
predictions_df = raw_streaming_df.withColumn("prediction", model(*raw_streaming_df.columns))display(predictions_df, streamName=stream_name)
一旦我们准备好预测结果,就可以将数据写入 Delta 表或适合我们使用场景的格式。
现在,让我们来看看如果我们想要执行实时推理,使用相同模型有多么简单。
部署 ML 模型进行实时推理
实时推理包括使用作为 REST 端点部署的模型对少量记录生成预测。期望在几毫秒内收到预测结果。
在特征仅在提供模型时可用且无法预先计算的使用场景中,需要进行实时部署。这些部署比批量或流式部署更复杂,需要更多的管理。
Databricks 提供集成的模型服务端点,使您能够在 Databricks 环境中,在生产级别的完全托管基础设施上原型设计、开发和部署实时推理模型。在撰写本书时,您可以利用以下两种额外方法将模型部署到实时推理:
-
由以下云服务提供商提供的托管解决方案:
-
Azure ML
-
AWS SageMaker
-
GCP VertexAI
-
-
使用 Docker 和 Kubernetes 或类似技术集的定制解决方案
如果您正在考虑为生产环境中部署和管理 ML 模型提供强大的解决方案,Databricks 模型服务提供了一系列引人注目的功能:
-
轻松创建端点:只需点击一下,Databricks 就会处理设置一个完全配备的环境,适合您的模型,并提供无服务器计算选项。
-
自适应可扩展性和可靠性:Databricks 模型服务为生产环境的高要求而设计,能够处理每秒超过 25,000 个查询的高吞吐量。该服务能够动态扩展以满足波动的需求,甚至允许多个模型在单一访问点上运行。
-
强大的安全措施:每个部署的模型都在安全的数字边界内运行,并分配专用计算资源,模型不再使用时会撤销这些资源。
-
与 MLflow 的顺畅集成:该平台轻松连接到 MLflow 的模型注册表,简化了 ML 模型的部署过程。
-
全面的监控和调试功能:Databricks 会捕捉所有请求和响应交互,并将其记录到专门的 Delta 表中,以便进行实时监控。查询速度、延迟和错误等指标会动态更新,并可以导出到您选择的监控解决方案中。
-
实时特征集成:如果您使用 Databricks 的特征存储训练了您的模型,这些特征会与模型无缝打包在一起。此外,如果您配置了在线特征存储,您还可以实时更新这些特征。
让我们了解一些与模型服务端点功能相关的重要技术细节,按类别分组。
Databricks 模型服务的约束和能力的深入分析
在本节中,我们将全面概述与使用 Databricks 模型服务相关的关键技术要点。从负载大小和查询吞吐量限制,到延迟和并发性指标,本节旨在为您提供基本的见解,帮助您有效地使用 Databricks 模型服务。此外,我们还将深入探讨系统资源分配细节,并讨论可能影响您操作的合规性和区域限制。最后,我们将触及可能影响您在该平台上部署机器学习模型决策的其他因素和操作见解。
-
负载限制和 查询吞吐量:
-
负载大小:值得注意的是,每个请求的负载大小限制为 16 MB。对于大多数标准用例来说,这已经足够,但对于更复杂的模型,可能需要进行优化。
-
每秒查询数(QPS):系统为每个工作空间设定了 200 QPS 的默认限制。尽管对于实验和低流量服务来说已经足够,但对于高需求场景,可以通过咨询 Databricks 支持将其扩展至 25,000 QPS。
-
-
延迟和 并发性指标:
-
评估延迟:那些使用计算密集型模型的用户需要注意,Databricks 对评估延迟设置了 120 秒的上限。
-
并发请求:在一个工作空间中,所有服务端点的并发限制为每秒 200 个查询。虽然这一限制通常足够,但对于需求更高的服务,可以通过 Databricks 支持进行自定义调整。
-
-
系统资源 和开销:
-
内存:该环境为每个模型分配默认的 4 GB 内存。对于大多数传统的机器学习模型来说,这通常是足够的,但深度学习模型可能需要扩展至 16 GB。
-
延迟开销:该架构的目标是将额外延迟保持在 50 毫秒以下,但这是一个尽力而为的近似值,而非保证。
-
-
合规性和 区域限制:
-
HIPAA 合规性:对于医疗领域的用户,需要注意的是,Databricks 模型服务目前不符合 HIPAA 合规性要求。
-
区域限制:某些情况下,工作区位置可能会干扰模型服务功能。这是规划阶段需要考虑的一个重要因素。要查看支持的区域列表,请访问
docs.databricks.com/en/resources/supported-regions.html
。
-
-
pandas.core.indexes.numeric
” 可能是由于 pandas 版本不兼容导致的。解决方法如下:-
运行 '
add-pandas-dependency.py
' (learn.microsoft.com/en-us/azure/databricks/_extras/documents/add-pandas-dependency.py
) 脚本,并使用 MLflowrun_id
。 -
在 MLflow 模型注册表中重新注册模型。
-
提供更新后的 MLflow 模型。
-
-
运营洞察:
-
端点创建时间:创建新模型端点的时间大约为 10 分钟。
-
零停机时间更新:该系统旨在执行端点更新时实现零停机时间,最小化运营风险。
-
动态扩展:Databricks 模型服务采用智能扩展算法,能够根据流量模式和预配置的并发性进行调整,确保资源的最优分配。
-
让我们来看一个如何使用 Databricks 内建的模型服务端点来开发、原型设计并部署模型以生成实时推理的示例:
- 转到工作区中的模型部分并选择客户流失预测 银行模型:
图 7.4 – 在模型注册表的 Staging 阶段注册的模型
- 点击用于推理的模型按钮:
图 7.5 – 用于推理的模型按钮,您可以选择使用模型进行批量/流推理或作为实时 REST 端点
- 选择实时并点击启用服务。在这里,我们可以选择要提供的模型版本以及服务端点的名称。还可以选择自动生成批量和流推理的代码:
图 7.6 – 如何从 UI 启用实时服务
- 您还可以指定希望为模型部署分配的计算资源类型。这取决于端点预计要处理的并发请求量。在我们的示例中,我们将选择小型:
图 7.7 – 各种计算选项
-
最后,您还可以选择扩展到零选项,以确保在没有负载时您的端点不会产生费用。现在,点击创建端点。
-
你将被重定向到状态页面,在这里你可以看到当前模型部署的状态,包括正在部署的模型版本:
图 7.8 – 部署的模型服务端点的状态页面
- 你还可以查看与模型部署相关的事件:
图 7.9 – 部署的模型服务端点的状态页面
你也可以对与端点相关的指标执行相同的操作:
图 7.10 – 与模型服务端点相关的指标
这里另一个需要注意的重要事项是,访问 REST 端点的权限是继承自你在模型注册表中设置的权限:
图 7.11 – 模型服务端点继承的权限
- 现在,让我们来看一下如何查询你的模型。在用户界面中,一旦你看到模型端点处于就绪状态,你可以点击服务端点状态页面右上角的查询端点按钮:
图 7.12 – 查询端点按钮
有一些代码片段可以解释如何在 Python、cURL 或 SQL 中查询你部署的特定版本的模型。还有一个选项可以模拟浏览器请求,以下步骤描述了如何使用它:
- 点击显示示例按钮。只有当我们在 MLflow 中记录了模型的输入示例时,这才有效:
图 7.13 – 来自 AutoML 的自动记录的示例输入记录
- 要向我们的模型发送 JSON 请求以进行实时推理,只需点击发送请求:
图 7.14 – 从部署的模型接收到的响应
当我们训练我们的客户流失预测模型时,AutoML 记录了我们的模型在作为 REST 端点部署时期望的示例输入。如果你没有使用 AutoML 而是自己训练模型,可以使用 MLflow API 在模型运行时记录模型的示例输入。
让我们看看如何借助示例笔记本使用 Python 查询模型端点:
-
打开
Chapter-07
文件夹中的Real-Time
笔记本。 -
要查询模型端点,我们需要每个 REST 调用都伴随一个 Databricks
Cmd 4
,我们必须从我们的笔记本实例中提取 PAT token,并以编程方式提取我们的工作区域名。这有助于保持代码与工作区无关:# get token from notebooktoken = dbutils.notebook.entry_point.getDbutils().notebook().getContext().apiToken().getOrElse(None)#create authorization header for REST callsheaders = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" }# Next we need an enpoint at which to execute our request which we can get from the Notebook's tags collectionjava_tags = dbutils.notebook.entry_point.getDbutils().notebook().getContext().tags()# This object comes from the Java CMtags = sc._jvm.scala.collection.JavaConversions.mapAsJavaMap(java_tags)# extract the databricks instance (domain name) from the dictionaryinstance = tags["browserHostName"]
-
Cmd 6
包含一种方法评分,该方法将作为输入的样本记录转换为 Python 字典,转化为 JSON 格式,并向已部署的模型发送请求。模型随后以 JSON 格式返回预测结果:# Import the requests library for HTTP communicationimport requests#change the model_serving endpoint name to the one you have given.model_serving_endpoint_name = "churn_prediction"# Define the function 'score_model' which takes a dictionary as an inputdef score_model(data_json: dict): # Construct the URL for the model serving endpoint url = f"https://{instance}/serving-endpoints/{model_serving_endpoint_name}/invocations" # Make an HTTP POST request to score the model response = requests.request(method="POST", headers=headers, url=url, json=data_json) # Check if the request was successful (HTTP status code 200) if response.status_code != 200: # If not, raise an exception detailing the failure raise Exception(f"Request failed with status {response.status_code}, {response.text}") # Return the JSON response from the model scoring endpoint return response.json()
-
为了有效地与服务端 API 进行交互,您应该根据已识别的格式之一组装 JSON 请求负载。每种格式都有独特的优点和限制。在我们的特定场景中,我们的 ML 模型期望以 pandas DataFrame 形式接收输入。因此,我们有两种最佳的结构化 API 查询端点的方向选项:
dataframe_split
方法,采用 JSON 格式并以分割方向序列化。与记录方向相比,这种格式更节省带宽,但阅读起来稍微复杂:
payload = { "dataframe_split": { "index": [1, 2], "columns": ["CreditScore", "Geography", "Gender", "Age", "Tenure", "Balance", "NumOfProducts", "HasCrCard", "IsActiveMember", "EstimatedSalary"], "data": [[619, "France", "Female", 42, 2, 0.0, 1, 1, 1, 101348.88], [608, "Spain", "Female", 41, 1, 83807.86, 1, 0, 1, 112542.58]] }}
records
布局是表示 DataFrame 数据的另一种选择。它以 JSON 对象的形式呈现,每个条目代表 DataFrame 中的一行。此记录易于阅读且对人类友好,但由于列名在每条记录中都会重复,因此会消耗更多带宽:
payload = { "record_dataframe": [ { "CreditScore": 619, "Geography": "France", "Gender": "Female", "Age": 42, "Tenure": 2, "Balance": 0.0, "NumOfProducts": 1, "HasCrCard": 1, "IsActiveMember": 1, "EstimatedSalary": 101348.88 }, { "CreditScore": 608, "Geography": "Spain", "Gender": "Female", "Age": 41, "Tenure": 1, "Balance": 83807.86, "NumOfProducts": 1, "HasCrCard": 0, "IsActiveMember": 1, "EstimatedSalary": 112542.58 } ]}
-
最后,您可以直接对这些记录进行推断调用:
score_model(payload){'predictions': [0, 0]}
当处理如 TensorFlow 或 PyTorch 等 ML 模型时,这些模型通常期望张量输入,您通常有两种主要的格式选项可供考虑:实例格式和输入格式。实例格式和输入格式各自具有独特的优缺点,这些优缺点会显著影响您 ML 解决方案的设计和性能。
让我们深入了解每种格式的细节,以便更好地理解如何最优化地使用它们:
-
张量的实例格式:实例格式专为张量数据设计,以行优先的方式处理张量。当所有输入张量在索引 0 的维度上共享相同的大小时,这种格式是理想选择。本质上,实例列表中的每个张量可以与列表中具有相同名称的其他张量进行概念上的合并,从而形成模型的完整输入张量。只有当所有张量在 0 维度上保持一致时,这种合并才是无缝的:
-
单一张量:
{"instances": [8, 9, 10]}
-
多个命名张量:
{ "instances": [ { "t1": "a", "t2": [1, 2, 3, 4, 5], "t3": [[1, 2], [3, 4], [5, 6]] }, { "t1": "b", "t2": [6, 7, 8, 9, 10], "t3": [[7, 8], [9, 10], [11, 12]] } ] }
-
-
张量的输入格式:输入格式是另一种将张量数据按列的方式结构化的选项。这种格式与实例格式在一个关键点上有所不同:它允许不同张量类型的实例具有不同的数量。这与实例格式相对,后者要求每种类型的张量实例数量一致。
Databricks 的服务功能提供了在单个端点后部署多个模型的灵活性,这对于进行 A/B 测试特别有用。此外,你还可以在同一个端点后将总流量的特定百分比分配给各个模型。有关更多详细信息,请参考官方文档(dpe-azure.docs.databricks.com/machine-learning/model-serving/serve-multiple-models-to-serving-endpoint.html#serve-multiple-models-to-a-model-serving-endpoint
)。
通过用户界面将另一个模型添加到现有端点是一个直接的过程。只需导航到编辑配置部分,选择添加已服务模型选项。在那里,你可以选择要部署的注册表中的模型,指定其版本,定义计算资源,并设置所需的流量分配:
图 7.15 – 如何将多个模型添加到同一个端点后
在Chapter-07
文件夹中,有一个名为real-time-additional
的笔记本,里面包含了演示如何使用 Python 编程通过 API 设置这些端点的代码。你可以按自己的节奏浏览它。
现在,让我们深入探讨与模型部署相关的其他常见场景。首先要介绍的是,在使用 MLflow 部署模型时,如何集成自定义用户定义的函数和库。
在 Databricks 部署中将自定义 Python 库集成到 MLflow 模型中
如果你的项目需要集成托管在安全私有仓库中的定制 Python 库或包,MLflow 提供了一个有用的实用函数add_libraries_to_model
。这个功能可以在日志记录过程中无缝地将这些自定义依赖项集成到你的模型中,然后通过 Databricks 模型服务进行部署。虽然以下代码示例使用 scikit-learn 模型演示了这一功能,但相同的方法可以应用于 MLflow 支持的任何模型类型:
-
上传依赖项并在笔记本中安装它们:推荐的上传依赖项文件位置是Databricks 文件系统(DBFS):
dbutils.fs.cp("local_path/to/your_dependency.whl", "dbfs:/path/to/your_dependency.whl")# Installing custom library using %pip%pip install /dbfs/path/to/your_dependency.whl
-
使用
mlflow.sklearn.log_model()
和pip_requirements
或conda_env
参数来指定依赖项:# Logging the modelimport mlflow.sklearncustom_requirements = ["scikit-learn", "numpy", "/dbfs/path/to/your_dependency.whl"]mlflow.sklearn.log_model(model, "sklearn-model", pip_requirements=custom_requirements)
-
add_libraries_to_model()
函数用于将自定义库与模型一起嵌入,以确保环境一致:import mlflow.models.utilsmodel_uri = "models:/<model-name>/<model-version>"mlflow.models.utils.add_libraries_to_model(model_uri)
-
模型部署:一旦新的模型版本,包括自定义库,已经注册,你就可以继续使用 Databricks 模型服务进行部署。
你可以在 MLflow 网站上阅读更多相关内容(www.mlflow.org/docs/latest/python_api/mlflow.models.html?highlight=add_libraries#mlflow.models.add_libraries_to_model
)。
这是另一个端到端的示例,你可以在 Chapter-07
文件夹中的 custom-python-libraries
笔记本中找到完整的代码:
# Model URI for accessing the registered modelaccess_model_uri = "models:/enhanced_model_with_libraries/1"
# Add libraries to the original model run
add_libraries_to_model(access_model_uri)
# Example to add libraries to an existing run
prev_run_id = "some_existing_run_id"
add_libraries_to_model(access_model_uri, run_id=prev_run_id)
# Example to add libraries to a new run
with mlflow.start_run():
add_libraries_to_model(access_model_uri)
# Example to add libraries and register under a new model name
with mlflow.start_run():
add_libraries_to_model(access_model_uri, registered_model_name="new_enhanced_model")
接下来,在以下章节中,我们将深入探讨自定义模型开发的细节,探索如何将专用算法、独特的数据处理技术和企业特定需求无缝集成到 MLflow 部署中,以提高性能和合规性。
使用 MLflow 和 Model Serving 部署自定义模型
部署机器学习模型通常不仅仅是进行预测。许多用例要求额外的功能,例如预处理输入、后处理输出,甚至为每个请求执行自定义逻辑。MLflow 中的自定义模型提供了这种灵活性,使得可以将专门的逻辑直接与模型集成。本节将带你了解如何使用模型服务(Model Serving)部署这些自定义模型。
MLflow 自定义模型在以下场景中特别有用:
-
预处理需求:当你的模型在将输入传递给预测函数之前需要特定的预处理步骤时。
-
后处理需求:当模型的原始输出需要转换或格式化以供最终用户使用时。
-
条件逻辑:如果模型本身有基于请求的分支逻辑,例如根据输入选择不同的模型或算法。
-
完全自定义代码:当你需要在模型旁边部署完全自定义的代码库时。
要在 MLflow 中创建自定义模型,你需要编写一个实现两个核心函数的 PythonModel
类:
-
load_context
:load_context
方法负责初始化诸如模型参数或第三方模块等关键组件,这些组件对于模型至关重要,但只需加载一次。这一步骤有助于提升模型预测阶段的性能。 -
predict
:该函数包含了每次收到输入请求时执行的所有逻辑。
以下是一些示例代码,定义了一个名为 CustomModel
的自定义 MLflow 模型类,该类使用 PythonModel
基类构建:
class CustomModel(mlflow.pyfunc.PythonModel): def load_context(self, context):
self.model = torch.load(context.artifacts["model-weights"])
from preprocessing_utils.my_custom_tokenizer import CustomTokenizer
self.tokenizer = CustomTokenizer(context.artifacts["tokenizer_cache"])
def format_inputs(self, model_input):
# insert code that formats your inputs
pass
def format_outputs(self, outputs):
predictions = (torch.sigmoid(outputs)).data.numpy()
return predictions
def predict(self, context, model_input):
model_input = self.format_inputs(model_input)
outputs = self.model.predict(model_input)
return self.format_outputs(outputs)
让我们更详细地了解这段代码,因为它可以根据你的用例在未来轻松修改。
-
load_context(self, context)
:load_context 方法初始化执行模型所需的基本资源。这些资源只加载一次,以优化推理阶段。让我们更详细地了解这个方法中的代码。-
self.model = torch.load(context.artifacts["model-weights"])
:这行代码从工件中加载一个 PyTorch 模型,并将其分配给self.model
属性。模型的权重应该是工件中的一部分,位于model-weights
键下。 -
from preprocessing_utils.my_custom_tokenizer import CustomTokenizer
:这行代码导入一个自定义的分词器类。 -
self.tokenizer = CustomTokenizer(context.artifacts["tokenizer_cache"])
:这行代码创建了一个导入的CustomTokenizer
类的实例,并使用标记为tokenizer_cache
的工件进行初始化。它被存储在self.tokenizer
属性中。
-
-
format_inputs(self, model_input)
:这个方法用于处理模型输入的格式化或预处理。到目前为止,这个函数的代码尚未实现,表示为pass
。到目前为止,这个函数的代码尚未实现,表示为
pass
。 -
format_outputs(self, outputs)
:这个函数负责对模型的原始输出进行后处理或格式化。-
predictions = (torch.sigmoid(outputs)).data.numpy()
:这行代码将 sigmoid 激活函数应用于原始输出,并将结果张量转换为 NumPy 数组。 -
这个函数用于格式化或后处理模型的原始输出。
-
-
predict(self, context, model_input)
:最后,我们有predict
方法,执行以下步骤:-
model_input = self.format_inputs(model_input)
:这行代码调用format_inputs
函数来格式化或预处理输入。 -
outputs = self.model.predict(model_input)
:这行代码使用预加载的 PyTorch 模型来生成预测结果。 -
return self.format_outputs(outputs)
:这行代码调用format_outputs
函数,在返回之前对原始输出进行后处理。
-
MLflow 允许你记录自定义模型,并附带你组织中共享的代码模块。例如,你可以使用code_path
参数来记录模型所需的整个代码库:
mlflow.pyfunc.log_model(CustomModel(), "model", code_path = ["preprocessing_utils/"])
mlflow.pyfunc.log_model(CustomModel(), "model", code_path = ["preprocessing_utils/"])
这一行使用 MLflow 的log_model
方法来记录一个自定义的 Python 模型,以便以后使用,比如提供服务或与团队成员共享。我们来分解一下函数参数:
-
CustomModel()
:这是你定义的自定义 Python 模型类的实例(例如我们之前看到的CustomModel
类)。这个模型将被记录,并可以以后从 MLflow 的模型注册表中检索。 -
"model"
:这是你为记录的模型指定的名称。它作为一个标识符,用于在 MLflow 中引用该模型。 -
code_path = ["preprocessing_utils/"]
:这是一个本地文件路径列表,指向自定义模型所依赖的 Python 文件。在此案例中,它表示preprocessing_utils
文件夹中的代码是自定义模型正常运行所必需的。这样做特别有用,当你希望包含一些必需的预处理或工具代码来运行模型时。在记录模型时,该目录中的代码将与模型一起打包。这确保了在后续加载模型时,你拥有所有必需的代码。
因此,当执行此函数时,它会将你的CustomModel
类实例作为名为“model”的模型记录到 MLflow 中。它还会将位于preprocessing_utils/
目录中的所有依赖代码一起打包。生成的工件可以在任何支持 MLflow 的地方加载和执行,且包含模型及其依赖项。
一旦你记录了自定义模型,它可以注册到 MLflow 模型注册表中,并像其他模型一样部署到模型服务端点。
让我们看一个完整的示例,展示自定义模型的使用。代码使用了葡萄酒数据集,这是一个经典且简单的多类别分类问题。具体来说,该数据集包含来自意大利三种不同葡萄品种的 178 个葡萄酒样本。每个样本有 13 个不同的特征,例如酒精含量、苹果酸等。
目标是根据这 13 个特征预测某个葡萄酒样本属于哪种葡萄品种。换句话说,给定一个新的葡萄酒样本,模型将预测它属于class_0
、class_1
或class_2
,每个类别代表三种葡萄品种之一。它还会提供该样本属于这些类别的概率。
该代码使用决策树分类器,该分类器在葡萄酒数据集的一个子集(训练集)上进行了训练。一旦模型训练完成,它就会被包装在一个自定义的 Python 类(CustomModelWrapper
)中,以便通过 MLflow 进行日志记录。
最后,模型用于对新的、未见过的数据(测试集)进行预测。此代码可在Chapter-07
文件夹中的custom-model
笔记本中找到:
# Custom model classclass CustomModelWrapper(mlflow.pyfunc.PythonModel):
# Initialize the classifier model in the constructor
def __init__(self, classifier_model):
self.classifier_model = classifier_model
# Prediction method
def predict(self, context, model_data):
# Compute the probabilities and the classes
probs = self.classifier_model.predict_proba(model_data)
preds = self.classifier_model.predict(model_data)
# Create a DataFrame to hold probabilities and predictions
labels = ["class_0", "class_1", "class_2"]
result_df = pd.DataFrame(probs, columns=[f'prob_{label}' for label in labels])
result_df['prediction'] = [labels[i] for i in preds]
return result_df
上述代码定义了一个CustomModelWrapper
类,该类继承自mlflow.pyfunc.PythonModel
。此类作为给定分类器模型的封装器。__init__
方法初始化分类器,而predict
方法计算概率和类别预测。然后,这些结果作为 pandas DataFrame 返回,其中包括每个类别的概率得分和最终预测的标签:
# Load the wine dataset and split it into training and test setswine_data = load_wine()
X, y = wine_data.data, wine_data.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=7)
# Initialize and fit the DecisionTreeClassifier
dt_classifier = DecisionTreeClassifier(random_state=7)
dt_classifier.fit(X_train, y_train)
# Create an instance of the CustomModelWrapper
custom_wrapper = CustomModelWrapper(dt_classifier)
# Define the input and output schema
input_cols = [ColSpec("double", feature) for feature in wine_data.feature_names]
output_cols = [ColSpec("double", f'prob_{cls}') for cls in wine_data.target_names] + [ColSpec("string", 'prediction')]
model_sign = ModelSignature(inputs=Schema(input_cols), outputs=Schema(output_cols))
# Prepare an example input
input_sample = pd.DataFrame(X_train[:1], columns=wine_data.feature_names)
input_sample_dict = input_sample.to_dict(orient='list')
# Log the model using MLflow
with mlflow.start_run():
mlflow.pyfunc.log_model("wine_model",
python_model=custom_wrapper, input_example=input_sample_dict, signature=model_sign)
从自定义模型包装器继续,代码采取额外步骤来准备模型的部署。首先,它加载葡萄酒数据集,并将其分为训练集和测试集。然后初始化并训练 DecisionTreeClassifier
,并在训练集上进行训练。接着,创建一个 CustomModelWrapper
实例,将训练好的分类器包装其中,添加了额外的输出格式化层。
下一阶段涉及定义输入和输出架构,通过指定特征和目标变量的数据类型及名称。这些架构作为模型预期输入和输出的蓝图,对于后续部署阶段至关重要。我们还使用训练集中的一行数据来构建示例输入,展示模型如何接收数据。
最后,模型被记录到 MLflow 中,不仅包括自定义包装器,还包括输入示例和预定义的架构。这种全面的记录确保模型在未来跟踪和部署时保持所有细节不变。
在 ML 部署管道中,确保所有模型依赖项正确打包对于稳定、可扩展和高效的运行至关重要。以下部分将详细说明使用 MLflow 将这些依赖项与模型一起打包的最佳实践。
与 MLflow 模型一起打包依赖项
在 Databricks 环境中,文件通常存储在 DBFS 中。然而,为了提高性能,建议将这些工件直接打包进模型工件中。这可以确保所有依赖项在部署时被静态捕获。
log_model()
方法不仅可以记录模型,还可以记录其依赖文件和工件。此函数接受一个 artifacts
参数,您可以在其中指定这些附加文件的路径:
Here is an example of how to log custom artifacts with your models: mlflow.pyfunc.log_model( artifacts={'model-weights': "/dbfs/path/to/file", "tokenizer_cache": "./tokenizer_cache"}
)
在通过 MLflow 记录的自定义 Python 模型中,您可以使用 context.artifacts
属性在模型的代码中访问这些依赖项:
class CustomMLflowModel(mlflow.pyfunc.PythonModel): def load_context(self, context):
self.model = torch.load(context.artifacts["model-weights"])
self.tokenizer = transformers.BertweetTokenizer.from_pretrained(
"model-base",
local_files_only=True,
cache_dir=context.artifacts["tokenizer_cache"]
)
在通过模型端点提供自定义模型时,所有的工件都会被复制到部署容器中。它们可以像示例中所示,通过上下文对象进行访问。
MLflow 允许您为模型指定 Conda 环境。您可以提供一个列出所有模型所需依赖项的 conda.yaml
文件。当您提供模型时,MLflow 会使用此 Conda 环境来确保所有依赖项正确安装。如果在记录模型时没有手动指定,该文件会自动创建。
这是一个在 Python 中指定 Conda 环境的示例:
mlflow.pyfunc.log_model( python_model=MyModel(),
artifact_path="my_model",
conda_env={
'name': 'my_custom_env',
'channels': ['defaults'],
'dependencies': [
'numpy==1.19.2',
'pandas==1.2.3',
'scikit-learn==0.24.1',
],
}
)
本章内容到此结束。让我们总结一下我们所学的内容。
总结
本章介绍了 Databricks 中的各种 ML 模型部署选项。我们还了解了多种部署范式,以及如何使用 Databricks 工作区实现这些范式。本书的后续版本将详细介绍 Databricks 正在开发的许多新功能,这些功能旨在简化 MLOps 旅程,为用户提供更好的支持。
在下一章,我们将深入探讨 Databricks 工作流,学习如何调度和自动化 ML 工作流。我们将介绍如何使用 Jobs API 设置 ML 训练。我们还将查看 Jobs API 如何与 webhooks 集成,以便在模型从一个注册表阶段转移到另一个阶段时,触发自动化测试。
进一步阅读
以下是一些进一步阅读的链接:
-
MLeap (
combust.github.io/mleap-docs)
) -
Databricks,DataFrames 简介 – Python (
docs.databricks.com/spark/latest/dataframes-datasets/introduction-to-dataframes-python.html
) -
结构化流处理编程 指南 (
spark.apache.org/docs/latest/structured-streaming-programming-guide.html
) -
Docker (
docs.docker.com/
) -
Kubernetes (
kubernetes.io/docs/home/
) -
Pickle – Python 对象 序列化 (
docs.python.org/3/library/pickle.html
)
第八章:使用 Databricks Jobs 自动化 ML 工作流
在上一章中,我们介绍了 ML 部署生命周期和各种模型部署范式。我们还理解了响应延迟、解决方案的可扩展性以及访问预测的方式在决定部署方法时的重要性。
在本章中,我们将深入探讨 Databricks 工作流 和 Jobs(之前称为 Databricks Jobs)。这个功能不仅可以用来定期安排模型的再训练,还可以通过我们在 第六章 中讨论的 webhook 集成触发测试,检查模型在从一个 模型注册表 阶段过渡到另一个阶段时的表现。
我们将覆盖以下主题:
-
理解 Databricks 工作流
-
利用 Databricks 工作流与 Jobs 自动化模型训练和测试
技术要求
以下是本章的技术要求:
-
至少需要拥有 无限制集群创建权限的 Databricks 工作区访问权限
-
按照之前描述的执行所有笔记本
现在,让我们来看看 Databricks 工作流。
理解 Databricks 工作流
工作流在最简单的意义上是用于开发和运行数据处理管道的框架。
Databricks 工作流提供了一项可靠的、完全托管的编排服务,用于处理 Databricks Lakehouse 平台上所有数据、分析和 AI 工作负载,支持任何云平台。工作流从 Databricks Lakehouse 平台开始设计,提供深度监控功能,并提供跨所有其他工作流的集中可观察性。客户使用 Databricks 工作流无需额外费用。
使用工作流的主要好处是用户不需要担心管理编排软件和基础设施。用户只需要专注于指定需要在工作流中执行的业务逻辑。
在 Databricks 工作流中,有两种方式可以使用托管工作流:
-
Delta Live Tables(DLT):DLT 是一个声明式的 ETL 框架,用于在 Databricks Lakehouse 平台上开发可靠的管道。DLT 允许轻松监控 ETL 管道,同时管理运行这些管道所需的基础设施。它还内置了期望功能,以便对每个 Delta 表的输入数据进行验证,并跟踪数据血缘,同时提供数据质量检查。DLT 提供了表级的详细数据血缘,并为 ETL 管道的所有部分提供统一的监控和警报功能。
DLT 本身是一个高级话题。深入讨论 DLT 的细节超出了本书的范围。我们将在 进一步阅读 部分提供一个链接,以帮助你开始使用 DLT。
下图展示了 DLT 中包含的功能:
图 8.1 – DLT 提供的所有功能
注意
Delta 管道用于纯声明式 ETL。你不能使用它们进行 API 调用或发送电子邮件。你应该使用 Delta 管道进行 ETL。对于其他所有任务,使用带有作业的工作流。我们将在下一节中从触发自动化模型重新训练和对模型注册表中更新的模型进行自动化验证的角度来介绍带有作业的工作流。
- 带有作业的工作流:作业是一种触发 Databricks 笔记本、库等执行的方式,可以立即执行或按照固定计划执行。我们将在本章中更详细地讨论这一点,重点是如何自动化你的 ML 工作流。
与几乎所有 Databricks 功能一样,你可以通过 UI、命令行接口(CLI)或 API 创建作业。你可以定义一个或多个任务作为工作流的一部分。任务可以包括执行以下选项之一:
-
一个Databricks 笔记本,该笔记本位于可在 Databricks 工作区访问的 Git 存储库中,或者位于工作区中的某个位置
-
在云存储中加载的Python 脚本,可以通过Databricks 文件 系统(DBFS)访问
-
编译为 JAR 文件的 Java 代码,此选项需要在集群上安装该 JAR 文件才能工作
-
DLT管道
-
spark-submit命令,这是一个允许将 Spark 或 PySpark 应用程序提交到底层集群的工具
-
Python wheel
你可以将多个任务串联在一起作为作业的一部分,并修复和重新运行失败或取消的作业。Databricks 还提供了通过 UI、CLI、API 和电子邮件通知监控作业状态的支持。如果你想了解如何使用 API 或 CLI 创建和管理带有作业的工作流,链接将在进一步阅读部分提供。Jobs 是一个非常灵活的工作流管理工具,可以用于开发和串联与 ETL 数据管道或 ML 工作流中各个步骤相关的任务。
让我们深入探讨如何使用 Databricks 中的带有作业的工作流功能,定期自动化机器学习模型的重新训练。工作流提供了精细的访问控制,允许所有者和管理员授予其他用户或小组查看工作流运行结果并管理工作流运行的权限。接下来,我们将更深入地探讨如何利用 Databricks 工作流与作业来自动化模型训练和测试。
利用 Databricks 带有作业的工作流自动化模型训练和测试
在本节中,我们将深入探讨 Databricks 工作流和任务之间的强大协同作用,以自动化机器学习模型的训练和测试。在开始实际操作之前,理解自动化在机器学习生命周期中的重要性,以及 Databricks 如何独特地解决这一挑战,至关重要。
在机器学习中,自动化训练和测试阶段不仅仅是一种便利,它是可扩展和高效的机器学习操作的必要条件。手动过程不仅耗时,而且容易出错,使得自动化成为现代 MLOps 中至关重要的一环。
这就是 Databricks 工作流发挥作用的地方,它允许复杂的机器学习管道的编排。
让我们看一个示例工作流,我们将使用工作流与任务来自动化它。我们将依次执行图 8.2中展示的以下逻辑步骤:
图 8.2 – 自动化测试和新模型推广警报的示例工作流
所有相关的代码都位于Chaper-08
文件夹中。让我们来看一下如何将 Databricks 笔记本作为工作流与任务一起安排:
- 我们首先导航到左侧导航栏中的
标签。在这里,我们可以点击创建任务:
图 8.3 – Databricks 工作流标签的内容
-
在这里,我们可以为任务提供一个名称,然后在类型下选择Notebook。在来源中,我们有两个选项 – 工作区和Git 提供者:
- 工作区:使用文件浏览器,您可以导航到您想要作为任务安排的工作区中的笔记本:
图 8.4 – 如何通过浏览工作区选项来浏览笔记本并将其安排为任务
您可以简单地导航到Repos
文件夹中的笔记本,如下图所示,然后点击确认:
图 8.5 – 如何通过 Repos 功能浏览笔记本并将其安排为任务
注释
在这里需要记住的一件重要事情是,当您使用 Databricks 的 Repos 功能时,它会为您的代码库创建一个本地副本或克隆。如果您在代码库中更改了代码,但没有在本地代码库中执行 Git 拉取最新版本,那么您的更新将不会传递到您正在安排的任务中,且任务使用的是当前版本的代码库。
对于生产部署,重要的是使用 Git 提供者作为来源,而不是使用工作区作为来源。
- Git 提供者:这种方法简化了在生产化和自动化部署过程中创建和管理作业的过程。这里的主要好处是,你可以在不管理多个代码仓库的权限的情况下对数据管道进行版本控制。你还将拥有一个统一的模型管道来源。每次作业执行时,它都会从远程仓库中拉取指定分支或标签的最新版本的笔记本/代码。Databricks 支持以下 Git 提供者:GitHub、Bitbucket Cloud、GitLab、Azure DevOps(不包括中国区域的 Azure)、AWS CodeCommit 和 GitHub AE。
注意
一个需要牢记的重要事项是,如果你使用 Git 提供者选项作为其中一个笔记本的来源,该笔记本将被安排为任务,你不能将其与使用工作区作为来源的笔记本任务混合在同一个作业工作流中。这一限制仅适用于使用 Databricks 笔记本。
要从 Git 提供者添加笔记本,输入你要访问笔记本的仓库详情。在我们的示例中,我将使用我自己为本书创建的 Git 仓库作为例子。
对于 路径,有几点需要注意:
-
你需要输入相对于笔记本位置的路径
-
不要在笔记本路径的开头添加
/
或./
字符 -
不要包括文件扩展名,例如
.py
-
要添加有关 Git 仓库的信息,请点击 添加 Git 引用,这将打开如 图 8.6 所示的窗口,在这里你可以选择你的 Git 提供者。
-
你可以选择从特定的 Git 分支/标签或提交执行笔记本。在我的例子中,我将使用 master 分支:
图 8.6 – 如何设置一个 Databricks 笔记本从仓库作为作业执行
选择集群时,你可以使用工作区中已经启动并运行的集群,也可以为工作流中的所有任务定义一个新的作业集群。我们已经在 第二章 中讨论了集群类型之间的差异。
-
最后,你还可以将参数传递给你的任务。在笔记本中,参数作为笔记本小部件传递。
如果你的使用场景需要设置 JAR、
spark-submit
命令、Python 文件或 Python wheel 作为任务,你可以将输入参数定义为 JSON 格式的字符串数组。对于 Python 任务,可以通过argparse
(docs.python.org/3/library/argparse.html
) Python 模块访问传递的参数。对于 Python wheel 任务,你还可以选择传递关键字参数作为键/值对,然后使用argparse
包访问这些参数。 -
在
1
中。这个设置在某些情况下很重要,尤其是当你需要与任务并行执行某个特定工作流时。如果请求执行工作流与任务的并行实例达到了最大并行运行次数,系统将跳过该请求。在我们的例子中,我们的笔记本任务没有任何依赖任务,所以我们只需点击创建。你还可以通过点击
图标来添加多个相互依赖的任务,作为工作流的一部分。
一旦我们成功创建了一个任务来作为工作流的一部分执行,我们可以在工作流部分的作业标签中看到关于我们工作流的信息。现在,我们可以选择通过立即运行按钮定期自动或交互式地调度工作流的运行。
我们可以看到一个图表,显示过去工作流执行的成功与失败,以及右侧显示的工作流与作业的运行时间和详细信息。请注意作业 ID,因为它将用于通过与模型注册表的 Webhooks 集成自动触发我们的模型测试笔记本:
图 8.7 – 监控作业运行历史记录以及唯一作业 ID、Git、调度、计算和通知设置的总结页面
让我们来看一下我们刚刚调度的Chapter-08
文件夹中自动化测试笔记本的内容:
-
Cmd 2
只是捕获由模型注册表 Webhook 发送的event_message
参数的值。它包含有关触发此笔记本工作流执行的事件的信息,例如以下内容:-
event_timestamp
:事件发生的时间 -
event
:事件的名称,如在 Webhooks 章节中描述的那样 -
text
:描述启动自动化测试执行的 Webhook 的目的 -
to_stage
:模型要转移到的目标阶段 -
version
:触发此 Webhook 的模型版本 -
from_stage
:模型版本在模型注册表中的初始阶段
根据我们正在调度的任务类型,Webhooks 的有效载荷会有所不同。如果你想了解更多,进一步阅读部分会提供一个链接。以下代码片段演示了从 Webhooks 获取和解析有效载荷的过程:
import jsonevent_message = dbutils.widgets.get("event_message")event_message_dict = json.loads(event_message)model_name = event_message_dict.get("model_name")print(event_message_dict)print(model_name)
-
-
Cmd 4
只是运行一些工具代码来与 MLflow REST API 进行交互。编写模块化代码以编写单元测试是一个很好的实践:import mlflowfrom mlflow.utils.rest_utils import http_requestimport jsondef client(): return mlflow.tracking.client.MlflowClient()host_creds = client()._tracking_client.store.get_host_creds()host = host_creds.hosttoken = host_creds.tokendef mlflow_endpoint(endpoint, method, body='{}'): if method == 'GET': response = http_request( host_creds=host_creds, endpoint="/api/2.0/mlflow/{}".format(endpoint), method=method, params=json.loads(body)) else: response = http_request( host_creds=host_creds, endpoint="/api/2.0/mlflow/{}".format(endpoint), method=method, json=json.loads(body)) return response.json()
-
在
Cmd 7
中,我们正在从 MLflow 模型注册表下载一个特定的模型版本来运行我们的测试:import mlflowpyfunc_model = mlflow.pyfunc.load_model(model_uri=f"models:/{model_name}/{version}")
其余的代码展示了如何编写任意测试,以在将模型提升到目标阶段之前对其进行测试。在示例代码中,我们测试了正在测试的模型是否具有输入所需的架构。我们还测试了响应的输出数据类型。
在测试成功运行结束时,我们向模型注册表发送一条消息,报告所有测试是否通过,供机器学习工程师审核:
# Leave a comment for the ML engineer who will be reviewing the testscomment = "This model passed all the tests"
comment_body = {'name': model_name, 'version': version, 'comment': comment}
mlflow_endpoint('comments/create', 'POST', json.dumps(comment_body))
有了这个,我们现在可以准备将automated-test
工作流与我们的模型训练笔记本进行注册。
让我们看看模型训练的代码。打开scheduling-workflow-for-model-retraining
笔记本。
这个笔记本首先包含注册一个作业 Webhook 的代码,用于在模型注册表中触发Churn Prediction Bank
模型的TRANSITION_REQUEST_TO_STAGING_CREATED
事件。
让我们一一查看笔记本中的重要单元格:
-
在
Cmd 2
中,我们仅从Python 软件包索引(PyPI)安装一个笔记本作用域的databricks-registry-webhooks
库。这是与 Databricks 模型注册表 Webhooks 交互的另一种方式,而不是使用我们在第六章中介绍的 Databricks REST API。 -
在
Cmd 3
中,我们仅从bank_churn_analysis
表中读取原始raw_data
表,并排除我们不会用来训练模型的特征。 -
Cmd 5
是一些实用代码,动态提取令牌和当前工作区的 URL。该代码可以放入独立的函数中,方便测试。 -
在
Cmd 7
中,我们将注册我们在步骤 1中创建的工作流,以便通过TRANSITION_REQUEST_TO_STAGING_CREATED
事件触发 Webhook。在代码中,将<jobid>
替换为你在步骤 2中记录的作业 ID
:from databricks_registry_webhooks import RegistryWebhooksClient, JobSpecjob_spec = JobSpec( job_id="<jobid>", workspace_url="https://"+instance, access_token=token)job_webhook = RegistryWebhooksClient().create_webhook( model_name=model_name, events=["TRANSITION_REQUEST_TO_STAGING_CREATED"], job_spec=job_spec, description="Registering webhook to automate testing of a new candidate model for staging")job_webhook
-
接下来,我们使用
AutoML
Python API 触发一个模型重新训练任务,主要指标是F1
得分:import databricks.automlmodel = databricks.automl.classify( new_data.select(features), target_col=target_column, primary_metric="f1", timeout_minutes=5, max_trials=30,)
-
接下来,我们仅使用
MLflowClient
类对象将表现最佳的模型注册到我们的模型注册表中:import mlflowfrom mlflow.tracking.client import MlflowClientclient = MlflowClient()run_id = model.best_trial.mlflow_run_idmodel_uri = f"runs:/{run_id}/model"model_details = mlflow.register_model(model_uri, model_name)
-
我们现在导入一些实用代码,它只是
MLflow REST API
的一个包装器,使用%run
魔法命令。这是你如何模块化代码,以便进行方便的测试和维护。%run ./mlflow-util
-
在
Cmd 17
中,我们请求将新模型版本过渡到暂存区。由于新模型在我们淘汰旧模型之前需要先进行测试,因此我们暂时不会将现有模型版本归档到暂存区。以下代码块演示了这一过程。staging_request = {'name': model_name, 'version': model_details.version, 'stage': 'Staging', 'archive_existing_versions': 'false'}mlflow_endpoint('transition-requests/create', 'POST', json.dumps(staging_request))
-
最后,我们还将添加一条评论,告知机器学习工程师模型已准备好进行测试:
comment = "This was the best model from the most recent AutoML run. Ready for testing"comment_body = {'name': model_name, 'version': model_details.version, 'comment': comment}mlflow_endpoint('comments/create', 'POST', json.dumps(comment_body))
有了这个,我们可以看到,在
Churn Prediction Bank
模型中,注册模型的一个新版本有一个待处理的请求。我们可以通过点击模型版本获取更多有关此模型的详细信息。这将显示我们请求模型过渡的情况,并显示训练后留下的评论:
图 8.8 – 我们通过 API 创建的请求模型过渡到 Staging 的消息
- 在请求过渡时,我们可以看到自动化测试现在正在执行新模型版本。通过点击
automated_test
,我们可以查看更多详情:
图 8.9 – 对任何请求过渡到 Staging 的新模型执行的自动化测试作业
矩阵视图显示了我们测试的当前状态。我们可以看到测试的实际输出:
图 8.10 – 我们的自动化测试作业运行的矩阵视图
- 在模型测试成功完成后,我们可以在模型 版本 页面查看状态:
图 8.11 – 在成功测试新模型后,消息成功发布到模型注册表
-
现在,ML 工程师或管理员可以归档旧模型并批准将此模型过渡到 Staging 环境的请求。
在我的情况下,这意味着将模型版本 2 过渡到归档:
图 8.12 – 如何将现有模型从 Staging 过渡到归档
- 我们可以添加一个评论,记录为什么这个模型被归档,这也将被记录在该模型版本的活动日志中:
图 8.13 – 如何在归档操作中添加消息
- 现在我可以批准模型版本 3 过渡到 Staging 并添加评论。当我们点击批准按钮时,我们可以批准模型过渡到 Staging,并将旧模型从 Staging 中退役:
图 8.14 – 如何批准新模型过渡到 Staging
这种方式在每次 Staging 环境中只有一个版本的模型时非常有用。如果你希望在某一阶段同时存在候选模型进行 A/B 测试,选择最佳模型后再进行退役,明确的退役操作会非常有帮助。
所以,现在我们已经执行了从训练新模型到在推广到 Staging 之前触发自动化测试的端到端工作流。
最后需要做的事情是安排每月的模型再训练。
- 返回
scheduling-workflow-for-model-retraining
笔记本并打开它。在每个 Databricks 笔记本的右上角,您会看到一个名为 Schedule 的按钮。点击该按钮后,您可以指定希望执行此笔记本的频率以及希望在哪种类型的集群上执行它。您还可以为笔记本添加参数并设置警报:
图 8.15 – 如何为自动化再训练设置模型
在我们深入探讨如何使用 Databricks Jobs 自动化机器学习工作流的复杂性后,您现在应该已经对如何设置和管理自动化 ML 再训练工作流有了扎实的理解。接下来,我们将在总结部分总结关键要点,帮助您巩固知识。
总结
本章中,我们讨论了在 Databricks 环境中可用的工作流管理选项。我们还更详细地探讨了带有 Jobs 功能的工作流,重点介绍了它在自动化 ML 工作流中的实用性。
我们演示了一个样本工作流,该工作流创建了一个包含测试的笔记本,以便对任何我们希望过渡到模型注册表 Staging 阶段的新模型进行测试。然后,我们配置了模型注册表 Jobs Webhook 功能,以便通过另一个自动化的模型再训练笔记本来触发该功能。类似的工作流可以使您的模型测试变得复杂多样,以满足您的需求。
在最后一章中,我们将介绍模型漂移的概念,以及如何自动触发模型的再训练。
进一步阅读
这里有一些链接可以进一步加深您的理解:
-
Databricks, 什么是 Delta Live 表格:
docs.databricks.com/en/delta-live-tables/index.html
-
Databricks, Databricks 入门 工作流:
docs.databricks.com/en/workflows/index.html
第九章:模型漂移检测与再训练
在上一章中,我们讨论了在 Databricks 中用于自动化机器学习(ML)任务的各种工作流管理选项。现在,我们将扩展我们迄今为止对 ML 生命周期的理解,并引入漂移的基本概念。我们将讨论为什么模型监控至关重要,以及如何确保你的 ML 模型随着时间推移仍然按预期表现。
在写这本书时,Databricks 正在开发一款产品,将简化模型性能和数据的监控。在本章中,我们将通过一个示例,展示如何使用现有的 Databricks 功能实现漂移检测和监控。
我们将涵盖以下主题:
-
模型监控的动机
-
模型漂移简介
-
统计漂移简介
-
漂移检测技术
-
在 Databricks 上实现漂移检测
让我们看看本章的技术要求。
技术要求
本章的先决条件如下:
-
访问 Databricks 工作区
-
一个运行中的集群,配备 Databricks 机器学习运行时(Databricks Runtime ML),版本高于 10.3
-
从第九章导入到 Databricks 工作区的笔记本
-
假设检验和统计测试解释的基础知识
让我们看看为什么模型监控如此重要。
模型监控的动机
根据 Enrique Dans 在 2019 年 7 月 21 日发表于《福布斯》杂志的文章,87% 的数据科学项目从未进入生产阶段(www.forbes.com/sites/enriquedans/2019/07/21/stop-experimenting-with-machine-learning-and-start-actually-usingit/?sh=1004ff0c3365
)。
机器学习模型失败的原因有很多;然而,如果我们单纯从生产环境中 ML 项目失败的原因来看,归根结底是因为缺乏再训练以及在生产环境中测试已部署模型的性能一致性。
模型的性能随时间不断下降。许多数据科学家忽视了模型生产后的维护。以下可视化展示了两种不同的模型管理方法——一种是模型训练一次后长时间部署,另一种是模型在监控性能漂移的同时定期用新数据重新训练:
图 9.1 – 静态模型与定期训练模型的质量比较
来源
感谢 Databricks 提供
有许多统计测试可以帮助我们监控模型性能随时间的变化,由于 MLOps 领域仍处于发展初期,机器学习从业者在如何以及选择哪些测试纳入其机器学习生产化过程中面临挑战。
本章将深入探讨我们建议使用哪些统计测试来监控生产环境中的机器学习模型。几种 Python 库可以无缝集成到 Databricks 环境中,用于此目的。这些库包括开源选项,如 whylogs、Evidently 和 Seldon Alibi Detect,它们提供从数据漂移追踪到全面的模型健康评估等多种功能。尽管本章的主要重点将放在如何利用统计测试进行 Databricks 内的模型监控,但我们鼓励你探索这些库,以增强你的监控工具集。Databricks 的灵活性使你可以轻松地将这些库集成到你的工作流程中,若你希望扩展到统计方法之外的其他方法。
我们还将讨论如何利用迄今为止学到的内容,使用开源工具在 Databricks 上实施模型监控。
我们将探讨的例子集中于使用表格数据集进行批量评分。然而,底层原则同样适用于涉及图像或文本数据的流式或实时推理。
各组织在自动化偏好上有所不同,尤其是在针对性能漂移进行模型再训练时。在本节中,我们的主要目标是审视各种模型监控策略。根据你的具体使用案例,你可以根据这些见解决定最合适的下一步行动。
为了更好地说明模型监控的定位,我们来看看机器学习项目的典型生命周期。
图 9.2 – 显示机器学习项目的生命周期
来源
感谢 Databricks 提供
任何机器学习项目的第一步是业务方提出他们认为可以从应用机器学习中获益的业务问题。作为此过程的一部分,相关利益方和数据科学家共同制定在线和离线指标。
离线指标是在训练机器学习模型时可以计算的指标,如准确率和 F1 分数。在线指标则是与业务相关的指标。
在确定了指标和成功标准后,数据科学家和机器学习工程师与数据工程师合作,理解所有可用的数据源,并确定哪些对于当前的业务问题有用。在前面的图示中,这一阶段被称为数据 收集阶段。
一旦数据收集完成,数据科学家将继续进行特征工程并训练各种机器学习模型,在评估模型后,他们将生产化最佳模型。
模型的生产化就是模型部署和监控的过程。整个过程,从收集数据到训练和评估模型,再到将最佳模型投入生产,都是一个迭代的过程。
将之前解释的整个过程付诸实践就是我们所说的 MLOps。所有的机器学习部署都各不相同,取决于我们要解决的领域和问题。
当你在 Databricks 上设计自己的机器学习解决方案时,应花费相当的时间来确定你将多频繁地训练和部署新模型,以及哪些性能监控和措施对于你的用例来说是合理的。
到目前为止,我们已经发现,随着时间推移,模型性能的下降是组织中机器学习项目失败的主要原因之一。现在,让我们来看一下模型性能为何可能随着时间而退化的一些原因。
模型漂移简介
机器学习模型可能会随着时间的推移而性能下降,这是项目中的常见问题。主要原因是输入到模型中的数据发生了变化。这些变化可能由于多种原因发生,例如数据的基础分布发生了变化,依赖特征与独立特征之间的关系发生了变化,或者生成数据的源系统发生了变化。
部署模型随时间的性能退化称为模型漂移。为了有效地识别模型漂移的实例,可以监控各种指标:
-
准确性:准确性下降的趋势可以作为模型漂移的强烈指示。
-
精确度和召回率:这些值的显著下降可能会突出模型在做出准确和相关预测方面能力的下降。
-
F1 分数:这是一个统一的度量,涵盖了精确度和召回率。F1 分数下降表明模型的整体效能受到影响。
-
业务指标:除了技术指标之外,关键的业务指标,如转化率、流失率和客户生命周期价值,也可以通过展示模型对业务目标影响的下降来揭示模型漂移。
模型漂移有许多类别,包括以下几种:
-
特征漂移:特征漂移指的是输入特征或预测变量的分布发生变化,这些特征或变量被机器学习模型用作输入。变化可能由于多种原因发生,例如数据收集过程的变化、测量误差,或数据源特征的变化:
- 例如,如果一个模型是在某个特定地点和时间段收集的数据上训练的,然后被部署到一个特征分布不同的其他地点或时间段,模型可能会遇到特征漂移。这可能导致模型性能下降,因为模型可能无法准确地泛化到新的特征分布上。
-
标签漂移:标签漂移指的是用于训练机器学习模型的输出标签或目标变量的分布变化。这些变化可能由于基础数据生成过程的变化、数据收集方法的变化或标签定义的变化而发生:
- 例如,如果一个模型通过历史数据训练来预测客户流失,而流失的定义随着时间变化,那么模型可能会经历标签漂移。这可能导致模型的预测与真实标签之间出现不一致,从而导致模型性能下降。
-
预测漂移:预测漂移指的是模型预测的分布随着时间变化而发生的变化。这种情况可能由于基础数据分布的变化、模型参数的变化或模型架构的变化而发生:
- 例如,如果一个模型用于预测股市价格并部署在动态的金融市场中,随着市场条件的变化,模型的预测可能会发生漂移。预测漂移可能会影响模型预测的可靠性和准确性,从而可能对业务或运营产生影响。
-
概念漂移:概念漂移指的是数据分布中变量之间的基础概念或关系随着时间变化而发生的变化。这种情况可能由于数据源的变化、数据生成过程的变化或所建模的基础现象的变化而发生:
- 例如,如果一个模型基于历史信用数据训练来预测信用风险,并且经济或监管环境发生变化,那么模型可能会经历概念漂移。概念漂移可能导致模型与现实世界现象之间的不一致,从而导致模型性能下降。
我们可以将有关各种漂移类型及其缓解措施的信息总结如下:
图 9.3 – 总结各种类型的漂移及我们可以采取的缓解措施
特征漂移、标签漂移和概念漂移共同归类为数据漂移。
理解并解决机器学习模型中的漂移至关重要,以确保它们在实际应用中的持续性能和可靠性。特征漂移、标签漂移、预测漂移和概念漂移是机器学习模型中可能发生的几种重要漂移类型。检测和缓解漂移需要使用适当的统计测试或方法来识别和量化数据分布随时间的变化。
在下一节中,我们将探讨另一个可能导致模型性能随时间恶化的重要因素——统计漂移。
统计漂移简介
统计漂移是指基础数据分布本身的变化。它可以影响输入特征和目标变量。这种漂移可能会或可能不会影响模型的性能,但理解它对更广泛的数据环境认知至关重要。
为了有效地识别统计漂移的实例,可以监控以下各种指标:
-
均值和标准差:显著的变化可能表明发生了漂移。
-
峰度和偏度:变化表明数据分布发生了改变。
-
分位数统计:例如,观察 25th、50th 和 75th 百分位数的变化。
为了全面理解模型漂移与统计漂移之间的相互关系,请考虑以下关键点:
-
因果关系:特征或目标变量的统计漂移通常是模型漂移的前兆。例如,若客户群体的年龄结构发生变化(显示统计漂移),则一个用来预测客户行为的模型可能会开始在性能上出现问题(导致模型漂移)。
-
同时发生:这两种漂移形式可以同时发生。例如,某电商模型可能因季节性变化而经历模型漂移,同时也由于客户群体的变化而发生统计漂移。
-
多样化的监控需求:每种类型的漂移都需要独特的监控策略。模型漂移通常通过检查预测误差来识别,而统计漂移通常通过观察数据分布的变化来检测。
-
不同的纠正措施:处理模型漂移通常涉及重新训练模型或进行微调。而统计漂移可能需要在数据处理协议或特征工程方面做出更全面的调整。
在做出选择使用哪种漂移检测方法的决策时,至关重要的是权衡每种方法的优缺点。你的选择将取决于项目的具体需求以及业务领域的细微差别。下表提供了一个简明的总结,突出了使用模型漂移检测方法与统计漂移检测方法的优点和挑战。
方面 | 模型漂移 检测方法 | 统计漂移 检测方法 |
---|---|---|
优点 | 通过性能指标易于检测;允许模型更新或再校准 | 提供对数据环境的更广泛理解,与模型无关 |
缺点 | 需要持续监控;可能会消耗资源 | 难以量化;可能需要复杂的测试;指示器不明显 |
表格 9.1 – 总结模型漂移检测方法与统计漂移检测方法的优缺点。
在下一部分中,我们将讨论可以用来监控特征和模型性能随时间变化的各种技术。
漂移检测技术
为了确保有效监控模型在时间上的表现,我们应追踪模型特征和目标变量的总结统计量和分布的变化。这将帮助我们早期检测到潜在的数据漂移。
此外,监控离线模型指标,如准确率和 F1 分数等,也很重要,这些指标是在模型最初训练时使用的。
最后,我们还应该关注在线指标或业务指标,确保我们的模型始终与我们要解决的特定业务问题相关。
以下表格提供了用于识别数据和模型漂移的各种统计检验和方法的概览。请注意,这个汇编并非包罗万象。
需要监控的数据类型 | 子类别 | 统计度量 和检验 |
---|---|---|
数值特征 | 总结统计量 | - 均值 |
- 中位数 | ||
- 最小值 | ||
- 最大值 | ||
- 缺失值计数 | ||
统计检验 | - Kolmogorov-Smirnov (KS) 检验 | |
- Levene 检验 | ||
- Wasserstein 距离 | ||
分类特征 | 总结统计量 | - 众数 |
- 唯一水平计数 | ||
- 缺失值计数 | ||
统计检验 | - 卡方检验 | |
目标-特征关系 | 数值型目标 | - 皮尔逊系数 |
分类目标 | - 列联表 | |
模型表现 | 回归模型 | - 均方误差 (MSE) |
- 错误分布图 | ||
分类模型 | - 混淆矩阵 | |
- 准确率 |
表格 9.2 – 用于检测各种类型漂移的监测表
对每一种统计检验进行详细讲解超出了本书的范围。我们将使用开源库来执行这些检验并检测漂移;然而,了解我们将在本章附带的示例笔记本中使用的一些检验的高层次步骤仍然是有益的。
首先,让我们理解假设检验的基础知识。所有统计检验都使用假设检验框架。
假设检验
当我们需要根据样本数据得出关于总体特征的结论时,假设检验是无价的。这个统计技术旨在检验不同数据集之间是否存在显著差异。让我们看看假设检验的核心步骤。
假设检验的核心步骤
假设检验的核心步骤有四个:
-
制定假设:
-
原假设 H0:该假设主张数据集之间没有显著差异。
-
备择假设 Ha:该假设主张数据集之间存在显著差异。
-
-
确定显著性水平:通常用α表示,该值表示当原假设为真时,拒绝原假设所犯的错误的可能性。常选用 0.05 作为α值,这对应于 5%的第一类错误风险。
-
计算检验统计量:这个数值度量来自样本数据和原假设,它是判断原假设有效性的依据。
-
确定 p 值:p 值量化了在原假设成立的情况下,获得已计算的检验统计量或更极端结果的可能性。这个度量标准指导我们是否应该接受或拒绝原假设。
-
做出最终决策
-
当 p−值 < α 时,原假设被拒绝。数据提供了充分的证据支持备择假设所提出的主张。
-
当 p−值 < α 时,原假设不被拒绝。支持备择假设的证据不足。
-
所以,现在我们了解了假设检验的基本知识。接下来,我们将回顾一些在本章附带的笔记本中用于演示漂移检测的统计检验步骤。
为了清晰地可视化我们将讨论的每个数值检验结果,附带的图形将基于一个合成数据集。这个数据集包含两个不同但可比较的数据点集,分别标记为“组 1”和“组 2”:
组 1
该数据集包括 1,000 个条目,使用均值为零、标准差为 1 的高斯分布生成。实质上,它是一个典型的钟形曲线,中心位于零。
第二组
该集合也包含 1,000 个条目。然而,这些条目来自均值为 1、标准差为 1 的高斯分布。其分布与组 1 相似,但在 x 轴上向右移动了一个单位。
定义特征
-
样本大小:组 1 和组 2 各包含相同数量的条目,从而实现平衡比较。
-
分布性质:两个组都遵循高斯分布,尽管中心值有所不同。
-
方差齐性:两个组的方差非常接近,使得它们适用于任何基于等方差假设的检验。
数值特征的统计检验和度量
在接下来的部分中,我们将深入探讨一系列统计技术,这些技术对于理解和分析数据集中的数值特征至关重要。我们将探索各种检验和度量方法,帮助你评估这些特征的质量、分布和关系,从而有助于有效的模型构建和监控。
Kolmogorov-Smirnov 检验
Kolmogorov-Smirnov(KS)两样本检验是一种非参数方法,用于评估两个独立数据集是否来自相同的分布,或它们的分布是否在统计上有显著差异。该检验侧重于比较两个数据集的经验累积分布函数(ECDFs)。要进行 KS 检验以检测我们数值特征中的漂移,按照以下步骤进行:
-
制定假设:
-
零假设(H0):该假设认为两个数据集来自相同的分布。
-
备择假设(H1):该假设认为两个数据集具有统计上不同的分布。
-
-
选择显著性水平(alpha)。这是决定是否拒绝零假设的临界点。常见的 alpha 值为 0.05 或 0.01。
-
计算检验统计量并根据 KS 检验的临界值表确定临界值或 p 值。
-
做出决策:
-
将在第 3 步中获得的 p 值与选择的显著性水平(alpha)进行比较。
-
如果 p 值小于 alpha,拒绝零假设,并得出结论认为组别或样本的方差不相等。
-
如果 p 值大于 alpha,保留零假设。这表明没有足够的证据表明分布是不同的。
以下图表描绘了经验累积分布函数(ECDFs)在组 1 和组 2 之间的情况。红色虚线表示两个 ECDF 之间的最大差异,量化了Kolmogorov-Smirnov(KS)统计量。图中展示了 KS 统计量和 p 值,提供了两组之间漂移的统计量度量。
图 9.4 – 使用描述的虚拟数据为“组 1”和“组 2”进行 Kolmogorov-Smirnov 检验的可视化
KS 统计量为 0.4310,p 值接近 0.0,表明两组之间的差异在统计上显著。从“漂移”的角度来看,这表明“组 1”和“组 2”之间的分布确实发生了显著变化或漂移。这在长期监测模型时尤为重要,特别是监测它们处理的数据是否发生变化。
需要注意的是,根据具体的应用场景,可能需要使用 Bonferroni 校正以减少假阳性的出现。
Levene t 检验
Levene 检验是一种统计检验,用于评估两个或更多组别或样本的方差是否相等。它是一个参数检验,当其他检验(如 t 检验或方差分析(ANOVA))所要求的方差相等假设(同方差性)无法满足时,可以使用 Levene 检验。Levene 检验可以通过以下步骤执行:
-
制定假设:
-
零假设(H0):这意味着组别或样本的方差相等。
-
备择假设(H1):这意味着组或样本的方差不相等。
-
-
选择显著性水平(alpha)。
-
计算检验统计量,并将其与 p 值进行比较。
-
做出决策:
-
将第三步中的 p 值与预设的 alpha 水平进行比较。
-
如果 p 值小于显著性水平(alpha),则拒绝零假设。这表明不同组或样本之间的方差不相同。
-
如果 p 值大于显著性水平(alpha),则保留零假设。这表明没有足够的证据证明方差存在差异。
-
箱线图显示了'Group 1'和'Group 2'的数据显示分布。每个组的方差被注释,并且 W 统计量和 p 值被呈现用于评估方差差异的统计显著性。
图 9.5 – Levene 检验的 W 统计量和 p 值
W 统计量较低,p 值较高,表明两个组之间的方差差异不显著。
Wasserstein 距离
也被称为地球搬运工距离,Wasserstein 度量用于衡量两个统计分布之间的相似性或差异。它计算将一个分布转化为另一个分布所需的努力,其中这些分布可以表示为直方图或离散的概率值集合。在识别数据漂移时,可以使用此度量来评估两个分布之间的差异程度,无论是随着时间推移还是在不同条件下。
在使用 Wasserstein 距离比较两个分布时,较高的 Wasserstein 距离值表示分布之间的差异或不相似性较大,而较低的 Wasserstein 距离值则表示分布之间的相似性或一致性较强。在数据漂移检测的背景下,Wasserstein 距离随时间或不同环境的增加可以表明数据漂移的存在,数据漂移指的是基础数据生成过程或分布的变化。
换句话说,如果两个分布之间的 Wasserstein 距离在时间推移或不同环境下显著增加,表明这些分布已经发生偏离,数据可能已经从原始分布中漂移。这可能是数据特征、数据生成过程或数据源发生变化的迹象。这可能促使进一步调查和监控,以确保数据质量和模型性能。作为数据漂移指示器,Wasserstein 距离的显著增加的阈值可能取决于具体问题或应用,需要仔细考虑和领域知识。
以下直方图展示了'组 1'和'组 2'的分布。紫色虚线视觉上表示 Wasserstein 距离,量化了将一个分布转换为另一个分布所需的“工作量”。
图 9.6 – 用于表示'组 1'与'组 2'之间的 Wasserstein 距离的可视化
Wasserstein 距离提供了一种衡量两个分布在位置和形状上的差异的方法。在本例中,距离值和紫色线条在分布中的分布表明,两个组之间存在一定程度的差异,但并不是极端的。
类别特征的统计检验和度量
本节中,我们将简要介绍最常用的检验之一:卡方检验。如前所述,所有统计检验都遵循前面部分描述的假设检验框架。
卡方检验
卡方检验是评估两个类别变量之间是否存在有意义关系的统计方法,通常以列联表的形式表示。一般的步骤包括以下几个步骤:
-
建立假设:
-
零假设 (H0):这表明两个类别变量之间不存在显著的关系。
-
备择假设 (Ha):这表示两个类别变量之间确实存在有意义的关系。
-
-
做出 决策:
如果卡方统计量的 p 值小于选定的显著性水平(alpha),则拒绝零假设。否则,接受零假设。
为了清晰地理解卡方检验,我们将基于一个合成数据集使用示意图。该数据集包含两个不同的类别,称为'组 1'和'组 2':
组 1
该集合包含 1,000 个条目。具体来说,572 个条目属于类别 'A',428 个条目属于类别 'B'。
组 2
该数据集也包含 1,000 个条目,其中类别'A'包含 447 个条目,类别'B'包含 553 个条目。
关键属性
-
样本大小:组 1 和组 2 都有相同数量的条目(N=1,000),从而使得公平的比较分析成为可能。
-
类别分布:每个组包含两个类别——'A' 和 'B'。然而,这些类别中的条目分布在不同组之间有所不同。
-
均匀样本大小:由于两个组都有 1,000 个条目,因此它们适合像卡方检验这样从平衡数据集中受益的统计检验。
下方的柱状图展示了'组 1'和'组 2'中类别 'A' 和 'B' 的频率。角落中的注释统计信息提供了计算出的卡方统计量、p 值和自由度,作为视觉比较的定量度量。
图 9.7 – 可视化展示'组 1'与'组 2'之间的卡方检验结果
极低的 p 值和高的卡方统计量表明'组 1'和'组 2'之间的类别分布存在统计显著差异。
为了方便参考,这里有一张表,详细列出了各种统计方法、它们的假设公式、决策标准和示例用例及指标。
方法 | 假设公式 | 决策标准 | 示例指标 | 特征类型 |
---|---|---|---|---|
T 检验 | 原假设:样本均值相同 | 备择假设:样本均值不同 | 如果 p 值小于显著性水平,则拒绝原假设 | 平均用户会话时长:5 分钟 vs 8 分钟 | 数值型 |
卡方检验 | 原假设:类别之间没有关系 | 备择假设:类别之间有关系 | 如果 p 值小于显著性水平,则拒绝原假设 | 各广告渠道的参与度 | 类别型 |
方差分析(ANOVA) | 原假设:组均值相同 | 备择假设:至少一个组均值不同 | 如果 p 值小于显著性水平,则拒绝原假设 | 不同销售单元的绩效指标 | 数值型 |
Kolmogorov-Smirnov 检验 | 原假设:数据分布匹配 | 备择假设:数据分布不同 | 如果 D 超过临界值,则拒绝原假设 | 各地区的客户年龄分布 | 数值型 |
Levene 检验 | 原假设:各组方差相等 | 备择假设:组间方差不同 | 如果 p 值小于显著性水平,则拒绝原假设 | 性别间的评分方差比较 | 数值型 |
Wasserstein 距离 | 原假设:分布相等 | 备择假设:分布不同 | 考虑特定领域的 Wasserstein 距离阈值 | 随时间变化的客户收入分布变化 | 数值型 |
表 9.3 – 统计方法的指南,包括假设、决策标准、示例用例和适用的特征类型。
现在我们已经简要介绍了用于检测单个特征漂移的统计检验。接下来,我们将讨论可以在模型上实施的监控测试。
模型的统计检验和测量
当涉及到整体监控模型性能时,我们可以针对以下内容进行额外监控:
-
你可以监控目标与独立特征之间的关系:
-
数值型目标:用于计算和监控皮尔逊相关系数
-
类别型目标:用于计算和监控列联表
-
-
模型性能:在这里,我们可以监控模型的离线指标随时间的变化:
-
回归模型:包括均方误差(MSE)、残差图、均方根误差(RMSE)等
-
分类模型:包括准确率、F1 分数、接收操作特性(ROC)曲线等
-
在保持数据集上的性能跟踪
-
-
训练所需时间:如果训练模型的时间随时间大幅增加,我们可能需要对此进行调查。
让我们来看一个在 Databricks 平台上检测漂移的端到端示例。我们将使用一个合成数据集,该数据集用于模拟各种类型的漂移。
在 Databricks 上实现漂移检测
本章所需的文件位于Chapter-09
文件夹内。这个示例演示了如何将代码组织成特定模块,以保持结构的清晰。
图 9.8 – 显示我们代码库中文件布局的截图
config
文件夹中的设置笔记本旨在建立用于数据读取和写入的文件夹结构。它还设置了用于跟踪模型性能的 MLflow 实验,并管理将会在我们的model
-drift
笔记本中使用的其他变量。
数据文件夹中的datagen
笔记本用于创建一个合成数据集,有效地展示模型漂移的概念。该数据集涵盖了一个电子商务网站的在线销售时间序列数据,时间跨度为三个月。
在这个数据集中,我们有一组独立特征和一个目标特征,以及它们之间的模拟关系。独立特征包括以下内容:
-
Temperature
(数值型):表示每日的最高温度,单位为华氏度 -
Weather_Condition
'sunny'
,'cloudy'
, 或'rainy'
-
Promotion_Type
'discount'
,'free_gift'
, 或'bundle_deal'
-
Website_Traffic
(数值型):表示网站的总访问量 -
Device_Type
(类别型):表示用于访问网站的设备类型
目标特征是Daily_Sales
(数值型),表示每天的总销售收入。
就关系而言,目标变量Daily_Sales
与这些特征有特定的相关性。例如,它与Temperature
和Website_Traffic
相关,而与Weather_Condition
和Device_Type
相关。
我们的方法是使用初始月份的数据训练模型,然后在接下来的几个月数据中模拟不同的漂移模式。这个过程使我们能够有效地探索数据分布和模式变化对模型性能的影响。
最后,util
文件夹中还有两个附加的笔记本。
monitoring
笔记本包含一组监控工具函数,旨在确保新到数据与生产数据在数据驱动环境中的质量和一致性。这些函数涵盖了各个方面,包括检查空值比例、识别总结统计量中的显著差异、检测方差和分布的变化、评估类别差异以及比较模型性能。该工具函数有助于维护数据完整性、识别潜在差异,并为将模型迁移到生产环境提供建议。此外,还提供了一个绘制箱型图的功能,用于可视化新到数据和生产数据之间的分布差异。
为了对数据执行各种统计检验,我们将使用scipy.stats
包。scipy.stats
是 SciPy 库的一个基本组成部分,广泛应用于 Python 中的科学和统计计算。它提供了一整套统计分布、函数和方法,用于执行各种统计计算、概率密度估计和假设检验。借助scipy.stats
,你可以轻松地处理连续和离散的概率分布、生成随机样本、计算统计量以及执行检验来分析数据。
该包涵盖了广泛的统计技术,例如计算概率、分位数、矩和进行拟合优度检验。scipy.stats
中提供的分布包括常见的正态分布、指数分布、均匀分布等,以及在各个研究领域中使用的较不常见和专业的分布。
除了统计分布,scipy.stats
还提供了假设检验、相关性分析、线性回归和非参数检验等函数。你可以在官方网站上了解更多信息(docs.scipy.org/doc/scipy/reference/stats.html
)。
training
笔记本专注于在 MLflow 环境中使用 scikit-learn 训练和管理机器学习模型。它包括与 MLflow 模型注册表交互、处理 Delta 表格和详细的机器学习工作流的工具函数。该工作流涵盖了数据加载、预处理、训练RandomForestRegressor
模型、评估性能以及将相关指标和工件记录到 MLflow 以进行模型跟踪。该脚本的目的是简化训练、评估和跟踪机器学习模型的端到端过程,尤其是在生产环境中。
在处理完所有支持的笔记本和高级代码说明后,接下来我们将介绍名为model-drift
的主驱动笔记本,它调用了所有其他笔记本。你可以在自己的时间里浏览支持的笔记本。
让我们直接进入model-drift
笔记本:
-
初始单元格只是调用其他支持性笔记本,以便为我们的示例准备所需的库、目录结构、原始数据集和 MLflow 实验:
%run ./config/setup%run ./util/training%run ./util/monitoring%run ./data/datagen
-
接下来,我们使用 Databricks 笔记本小部件来参数化我们的笔记本,以设置假设检验和模型性能指标的某些阈值:
# Remove all existing widgetsdbutils.widgets.removeAll() # Create three widgets for the stats threshold limit, p-threshold, and min model R2 thresholddbutils.widgets.text("stats_threshold_limit", "0.5")dbutils.widgets.text("p_threshold", "0.05")dbutils.widgets.text("min_model_r2_threshold", "0.005")# Get the values of the widgets# stats_threshold_limit: how much we should allow basic summary stats to shiftstats_threshold_limit = float(dbutils.widgets.get("stats_threshold_limit"))# p_threshold: the p-value below which to reject null hypothesisp_threshold = float(dbutils.widgets.get("p_threshold"))# min_model_r2_threshold: minimum model improvementmin_model_r2_threshold = float(dbutils.widgets.get("min_model_r2_threshold"))
-
从存储为 CSV 文件的原始合成数据集中提取第一个月的数据,并将其导入 Delta 表:
# Ensure we start with no existing Delta tabledbutils.fs.rm(months_gold_path, True) # Incoming Month 1 Dataraw_data = spark.read.csv(raw_good_data_path, header=True, inferSchema=True)# Filter the DataFrame to only include data for January 2023raw_data_month1 = raw_data.filter(raw_data["Date"].between("2023-01-01", "2023-01-31"))import pyspark.sql.functions as F# Create inital version of the Gold Delta table we will use for training - this will be updated with subsequent "months" of dataraw_data_month1.withColumn("month", F.lit("month_1")).write.format("delta").mode("overwrite").partitionBy("month").save(months_gold_path)
-
使用我们自定义的方法
train_sklearn_rf_model
作为 MLflow 运行来训练基准模型。这个运行将可以在我们的实验中查看:# read gold data for month 1 from the Delta tablemonth1_gold_delta_table = DeltaTable.forPath(spark, path=months_gold_path)month1_gold_df = month1_gold_delta_table.toDF()# Set the month number - used for naming the MLflow run and tracked as a parameter month = 1# Specify name of MLflow runrun_name = f"month_{month}"target_col = "Daily_Sales"cat_cols = [col[0] for col in month1_gold_df.dtypes if col[1]=="string" and col[0]!='month']num_cols= [col[0] for col in month1_gold_df.dtypes if ((col[1]=="int" or col[1]=="double") and col[0]!="Daily_Sales") ]print(f"category columns : {cat_cols}")print(f"numeric columns : {num_cols}")print(f"target column : {target_col}")# Define the parameters to pass in the RandomForestRegressor modelmodel_params = {"n_estimators": 500, "max_depth": 5, "max_features": "log2"}# Define a dictionary of parameters that we would like to use during preprocessingmisc_params = {"month": month, "target_col": target_col, "cat_cols": cat_cols, "num_cols": num_cols}# Trigger model training and logging to MLflowmonth1_run = train_sklearn_rf_model(run_name, months_gold_path, model_params, misc_params)month_1_run_id = month1_run.info.run_id
-
将我们在第一个月的数据上训练的基准模型注册到模型注册表,并将其状态更改为生产环境:
# Register model to MLflow Model Registrymonth_1_model_version = mlflow.register_model(model_uri=f"runs:/{month_1_run_id}/model", name=mlflow_experiment_name)# Transition model to Productionmonth_1_model_version = transition_model(month_1_model_version, stage="Production")print(month_1_model_version)
-
让我们深入了解训练基准模型后生成的运行。找到位于笔记本右侧的 Flask 图标,并点击它以访问该运行。需要注意的是,运行名称可能会有所不同,因为它是随机生成的。
图 9.9 – 显示使用第一个月数据进行基准模型训练的运行跟踪截图
除了度量指标外,我们的自定义模型训练方法还包含记录用于训练模型的数据集摘要统计信息的代码。
图 9.10 – 显示训练数据集的记录摘要统计信息截图
- 此外,我们还记录了用于训练模型的 Delta 表的确切版本。如果将来需要分析此模型的训练过程以及训练中使用的特征,这将为我们提供可重现性和溯源信息。
图 9.11 – 记录 Delta 表版本以及用于此次运行的训练集和测试集大小的截图
在笔记本的其余部分,我们仅使用此基准模型来比较模型性能。
-
对于第二个月的数据,我们通过引入某些推广类型的
website_traffic
缺失值和将温度的测量单位从华氏度改为摄氏度来模拟上游数据错误。通过执行检查所有数值列的空值比例的测试,我们能够捕捉到web_traffic
有异常的缺失值:print("\nCHECKING PROPORTION OF NULLS.....")check_null_proportion(month_2_pdf, null_proportion_threshold=.5)
图 9.12 – 显示对新数据进行空值检查的结果截图
-
为了检测数据中的漂移,我们使用在监控笔记本中定义的
calculate_summary_stats
方法来计算第二个月数据的摘要统计。然后,我们使用其他实用方法,如load_summary_stats_pdf_from_run
,从我们的基础运行中读取摘要统计,以便将第二个月的数据进行比较:# Incoming Month 2 Dataraw_data_month2 = spark.read.csv(raw_month2_bad_data_path, header=True, inferSchema=True)# Filter the DataFrame to only include data for Feb 2023raw_data_month2 = raw_data_month2.filter(raw_data_month2["Date"].between("2023-02-01", "2023-02-28"))# Print the filtered DataFrameraw_data_month2.show(5)# Compute summary statistics on new incoming data# we will keep only the columns that we monitored for the last mode training data# convert to pandas dataframe should be used with care as if the size of data is larger than what can fit on driver node then this can cause failures.# In the case of data size being large use proper sampling technique to estimate population summary statistics.month_2_pdf = raw_data_month2.toPandas().drop(['Date'], axis=1)summary_stats_month_2_pdf = calculate_summary_stats(month_2_pdf)summary_stats_month_2_pdf# Get the original MLflow run associated with the model registered under Productioncurrent_prod_run = get_run_from_registered_model(mlflow_experiment_name, stage="Production")# Load in original versions of Delta table used at training time for current Production modelcurrent_prod_pdf = load_delta_table_from_run(current_prod_run).toPandas()# Load summary statistics pandas DataFrame for data which the model currently in Production was trained and evaluated againstcurrent_prod_stats_pdf = load_summary_stats_pdf_from_run(current_prod_run, project_local_tmp_dir)print("\nCHECKING PROPORTION OF NULLS.....")check_null_proportion(month_2_pdf, null_proportion_threshold=.5)statistic_list = ["mean", "median", "std", "min", "max"]unique_feature_diff_array_month_2 = check_diff_in_summary_stats(summary_stats_month_2_pdf, current_prod_stats_pdf, num_cols + [target_col], stats_threshold_limit, statistic_list)unique_feature_diff_array_month_2
我们的摘要统计比较检验能够捕捉到数据中的漂移,并突出显示新数据中温度发生了剧烈变化。
图 9.13 – 截图展示了通过统计检验生成的输出,比较了新一个月的数据与基准数据的摘要统计
-
接下来,我们将使用 Levine 检验来评估方差的变化,并结合修正过的 Bonferroni 检验来确定统计显著性:
print("\nCHECKING VARIANCES WITH LEVENE TEST.....")check_diff_in_variances(current_prod_pdf, month_2_pdf, num_cols, p_threshold)print("\nCHECKING KS TEST.....")check_dist_ks_bonferroni_test(current_prod_pdf, month_2_pdf, num_cols + [target_col], p_threshold)
-
作为生产阶段的下一步,你可能需要与上游数据提供团队合作,了解与我们基础数据集相比,温度值为何发生如此剧烈的变化。
所展示的检验方法作为示例,突显了在 Databricks 的机器学习工作流中无缝集成漂移检测代码的重要性。值得注意的是,这些检验可以轻松地自动触发,类似于在第八章中展示的自动化示例,使用 Databricks 作业自动化机器学习工作流。
随着你继续浏览剩余的笔记本内容,你将遇到更多示例,这些示例阐明了如何随着时间的推移追踪模型指标以检测性能退化。此外,你还将获得关于如何通过编程管理模型在生产阶段或其他阶段的推进的见解,这一过程依赖于你从测试中得出的结果。
让我们总结一下本章的内容。
总结
在本章中,我们深入探讨了监控模型和数据的重要性,强调了漂移检测的关键作用。通过深入了解我们可以使用的各种统计检验方法,我们加深了对这一领域的理解,这些方法能够有效识别涵盖数值和分类特征的各种漂移形式。
此外,我们还进行了全面的演练,示范了这些概念的应用。通过使用合成的电子商务数据集进行模拟模型漂移场景,我们运用了scipy.stats
包中的各种统计检验方法,准确地识别出了漂移的实例。
随着我们进入下一章,焦点将转向阐明 Databricks 工作区的组织结构,并深入探讨持续集成/持续部署(CI/CD)领域。
第十章:使用 CI/CD 自动化模型再训练和重新部署
在第九章中,我们通过 Databricks 上多种开源库及其与 MLflow 的集成,探讨了多种统计测试,现在我们将重点关注 Databricks 上 MLOps 的一个核心组成部分。在本章中,我们将研究 Databricks 如何将 DevOps、DataOps 和 ModelOps 统一到一个平台中。
本章将涵盖以下主题:
-
MLOps 简介
-
MLOps 基础与部署模式
让我们来理解一下什么是 MLOps。
MLOps 简介
MLOps 作为一种多学科的方法,融合了 DevOps、ModelOps 和 DataOps 的原则,旨在促进机器学习项目的端到端生命周期。它的目标是简化从模型开发到部署的过渡,同时确保有效的监控和管理。在这一框架中,我们有以下内容:
-
DevOps:专注于代码的持续集成和部署,旨在实现更快的发布和更可靠的软件。
-
ModelOps:专注于管理 ML 模型,确保它们经过有效的训练、验证和部署。
-
DataOps:涉及数据管理实践,涵盖从数据收集、预处理到存储和分析的各个方面。
MLOps 提高了 ML 系统的性能、稳定性和长期效率。MLOps 可以帮助减轻你的用例和行业中的两大主要风险:
-
技术风险:这些风险来源于管理不当的模型,这些模型未能按预期表现。若没有 MLOps 来实施你的基础设施和管道以训练新模型并将其重新部署到生产环境中,它可能非常脆弱。
-
合规风险:如果你属于受监管行业,必须跟踪新的法规和合规要求以确保不违反它们,MLOps 可以帮助减轻这些风险。
通过自动化,MLOps 还可以在进入生产环境之前减少并捕捉错误,缩短推出和维护依赖于最新模型的产品的上市时间。
现在,让我们看一下 Databricks 作为一个平台,它可以帮助减少之前提到的风险,并帮助提高团队和 ML 项目的长期效率。
Databricks 的一个独特之处在于它是一个数据驱动的 AI 平台。作为这个 AI 平台的一部分,Databricks 独特地提供了管理 ML 项目中数据、模型和代码所需的所有必要组件。
为了阐明 Databricks 如何促进 MLOps,以下图表展示了该平台与 Databricks 湖仓平台上的各种工具和服务的集成能力:
图 10.1 – Databricks 的数据驱动平台及其组件
注意
由 Databricks 提供。
接下来,我们将探讨 Delta Lake 如何作为一项关键技术,弥合强大数据存储与机器学习准备之间的差距。
Delta Lake —— 不仅仅是一个数据湖
在管理复杂的数据生态系统时,Databricks 提供了 Delta Lake,这是一层综合性的开源存储层,我们在第一章中简要讨论过它。对于更深入的阅读,我的几位尊敬的同事也撰写了关于这一主题的其他详细书籍,它们列在本章的进一步阅读部分。
Delta Lake 凭借增强大数据处理框架,特别是 Apache Spark 的可靠性、可扩展性和性能而脱颖而出。由 Databricks 开发,它为数据湖提供原子性、一致性、隔离性和持久性(ACID)事务及强大的模式强制执行能力。这一点尤为关键,因为干净且可靠的数据不仅仅是一个优势,更是任何严肃数据工程或机器学习计划的前提条件。
为什么需要更清洁的数据和强大的数据工程管道?
在 Delta Lake 中拥有干净的数据和强大的数据工程管道,不仅是运营效率的问题,更是战略上的必要条件。数据质量直接影响机器学习模型的准确性、预测能力,最终影响商业结果。不一致或噪声数据可能误导算法,导致错误的洞察和决策。通过强制执行严格的模式并提供 ACID 事务,Delta Lake 将数据湖从单纯的存储库提升为能够有效处理机器学习算法复杂性的敏捷数据平台。
高效的管道同样至关重要。它们加速了从数据采集到洞察和模型部署的流动。缓慢或中断的管道会成为机器学习项目的瓶颈,导致组织在时间和资金上的损失。Delta Lake 的事务能力和元数据管理有助于构建不仅高效,而且具有韧性和未来适应性的管道。
访问控制在机器学习建模中的作用
随着机器学习(ML)成为业务流程的核心,数据访问的安全性和控制需求愈加迫切。在这里,Delta Lake 的基于角色的访问控制(RBACs)发挥了重要作用,与组织身份管理系统无缝集成。这确保了敏感数据仅能被授权人员访问,从而增加了一层安全保障,有助于满足合规性要求并保护机器学习模型的完整性。
Delta Lake 的主要特点包括以下几点:
-
ACID 事务:Delta Lake 确保数据操作的原子性、一致性、隔离性和持久性,允许并发读取和写入。它提供事务性保证,让你可以放心地执行复杂的数据操作。
-
模式演化:Delta Lake 支持模式强制执行,允许你为数据指定并演化模式。它通过拒绝写入不兼容的模式来强制执行数据质量,并提供模式演化功能来处理随时间变化的模式。
-
时间旅行:Delta Lake 保持数据的完整历史版本,允许你在任何时间点查询和分析数据。你可以轻松跟踪变更并比较数据的不同版本,这对于审计、调试和重现分析非常有价值。
-
优化的数据处理:Delta Lake 利用先进的索引和缓存机制来优化查询性能。它通过使用统计信息和优化手段,在查询执行过程中跳过不必要的数据,从而提高响应速度。
-
数据湖元数据管理:Delta Lake 将元数据存储在事务日志中,实现自动模式发现和高效的表元数据管理。它提供数据血缘信息,使得理解数据流动和转换过程变得更加容易。
Delta Lake 与 Apache Spark 高度兼容,允许你在数据湖上利用 Spark 强大的分析能力。它在数据湖架构中获得了广泛的应用,使得数据工程师和科学家能够构建稳健、可扩展和可靠的数据处理管道。
接下来,我们将探讨 MLflow 在 Databricks 平台中的无缝集成,它提供了端到端模型管理的强大功能。我们还将深入了解新兴领域——ModelOps。
使用 Databricks MLflow 进行全面的模型管理
在管理模型方面,Databricks 提供了托管的 MLflow,我们在之前的章节中已经深入讲解了这一部分内容。
MLflow 是一个开源平台,旨在简化机器学习生命周期。它提供了一整套工具和 API,用于管理、追踪和部署机器学习模型。MLflow 由 Databricks 开发,并在机器学习社区中得到了广泛的采用。
MLflow 包含四个主要组件:
-
跟踪:MLflow Tracking 允许你记录并跟踪与机器学习项目相关的实验、参数、指标和工件。它提供了一个统一的界面,用于记录和比较不同实验的运行结果,使得重现结果和迭代模型变得更加容易。Tracking 还支持与 ML 框架的集成,如 TensorFlow、PyTorch 和 scikit-learn。
-
项目:MLflow Projects 提供了一种标准格式,用于打包和共享机器学习代码。通过 MLflow Projects,你可以将机器学习代码定义为可重用的项目,包含代码、依赖项和配置。这确保了代码可以在不同环境中轻松执行,从而实现可重现性和协作。
-
模型:MLflow 模型使您能够以多种格式管理和部署机器学习模型。它提供了一种简单的模型格式,允许您将模型及其相关元数据和依赖项打包。然后,您可以将这些模型部署到各种部署环境中,如批量评分、实时服务或云平台。
-
模型注册表:MLflow 模型注册表是一个可选组件,它为 MLflow 模型增加了模型版本控制、阶段转换和协作功能。它使您能够跟踪不同版本的模型,推动模型通过不同的阶段(例如,从预发布到生产),并管理不同团队成员的访问控制。
MLflow 支持多种编程语言,包括 Python、R 和 Java。它既可以在本地开发环境中使用,也可以在分布式集群中使用,适合不同的部署场景。
在我们从讨论使用 Databricks MLflow 进行模型管理过渡时,让我们深入探讨 DevOps 和 MLOps 之间的协同作用,以及这些原则如何在 Databricks 生态系统中被适配和扩展,以支持强大的 ML 管道。
在 Databricks 中整合 DevOps 和 MLOps,以构建强大的 ML 管道
Databricks 与著名的 Git 服务提供商(如 GitHub、GitLab 和 Azure DevOps)集成,用于管理和执行我们的 ML 项目的 DevOps 工作流。
DevOps 结合了软件开发(Dev)和 IT运维(Ops),促进了协作、自动化和持续交付。它旨在简化软件系统的开发、部署和维护。
通过引入 DevOps 原则,MLOps 为机器学习模型的生命周期增添了一层效率。它促进了各个阶段之间的紧密协作——从开发和验证模型到它们的部署、监控、再训练和重新部署。
在 MLOps 领域,持续集成和持续交付(CI/CD)成为了关键要素。它们支撑了自动化,并推动了 ML 系统中的持续学习。CI/CD 的最终目标是无缝地将数据与源代码版本集成,执行由相关事件触发的并行任务,编译工件,并将发布传播到生产阶段。
通过结合持续集成(CI)和持续交付(CD)原则进行持续学习,对于机器学习(ML)系统的成功至关重要。没有这一点,系统可能会陷入停滞,变成一个毫无成效的概念验证(POC)。持续的学习和适应使得机器学习模型能够提供有价值的商业洞察。
为了使用不断改进的机器学习模型,您需要理解 CI、CD 和相关方法。它们是相互协作且相互依赖的,如图 10.2所示:
图 10.2 – 持续集成、持续交付和持续部署之间的关系
让我们稍微详细了解这些方法:
-
持续集成:在 MLOps 中,CI 不仅仅是测试和验证代码,还扩展到测试和验证数据、数据架构以及 ML 模型。这确保了一个更强大、更可靠的集成过程,专为 ML 需求量身定制。
-
持续交付:在 MLOps 中,CD 不仅仅是部署单一的软件包或服务,而是部署整个系统,通常包括 ML 训练管道和模型预测服务。
-
持续部署:与传统的 DevOps 类似,MLOps 中的 CD 更进一步,通过完全自动化发布过程,将新变化部署到生产环境中,而无需人工干预。
-
持续训练:这是机器学习系统独有的,CT 专注于自动化重训练和服务模型,确保模型随着时间的推移不断适应和改进。
在编写本书时,Databricks 正在开发一个名为 MLOps Stack 的新功能,它提供了一个模板,用于将复杂的 ML 项目结构化,以便与 Git 提供者进行 CI/CD 集成。
想要了解更多关于 MLOps Stack 的细节,建议访问GitHub 上的 MLOps Stack (github.com/databricks/mlops-stack
)。
本章将不会涉及 MLOps Stack;相反,我们将介绍另一种基于迄今为止所学知识,在 Databricks 上构建 MLOps 管道的方法。
让我们深入探讨并理解 MLOps 的基本原理和各种部署模式。
MLOps 基础与部署模式
为了有效管理 MLOps,首先必须熟悉其基础术语和结构。这包括理解与各种操作环境相关的角色和职责——即开发(dev)、预生产环境和生产(prod)。让我们从实际的 MLOps 框架中解析这些环境的含义。
在任何 ML 项目中,都有三个关键资产:
-
代码库:这作为项目的蓝图,包含与数据预处理、模型训练、评估和部署相关的所有源代码。
-
数据:这包括用于训练、验证和测试模型的数据集。数据的质量和可用性直接影响模型的效果。
-
训练模型:这是你 ML 工作流的最终成果,一个经过训练、评估并准备好进行推理的模型。
这些资产每个都经历不同的阶段——开发、测试和部署——通常这些阶段被分隔到不同的环境中:
-
开发环境(dev):这是初始代码编写和测试的地方。通常在代码和数据方面最为便捷,但质量和测试要求最为宽松。
-
预发布环境:这是一个中间空间,用于在项目进入生产阶段之前进行额外的测试和质量保证。
-
生产环境(prod):这是最具限制性的环境,最终版资源会部署在此。它有最高的质量和安全要求,且对直接交互的访问最为有限。下图提供了 MLOps 中关键资源的可视化表示,并展示了不同环境的组织结构。它展示了这些资源从开发、测试到最终生产的生命周期:
图 10.3 – 与机器学习项目及其环境相关的各种资源
注意
上述图由 Databricks 提供。
下图展示了这些环境中的可访问性级别和质量要求:
图 10.4 – 各种环境及其对可访问性的开放程度
注意
上述图由 Databricks 提供。
使用 Databricks,你可以灵活地以多种方式结构化这些开发、预发布和生产环境,以满足项目的特定需求。
需要注意的是,开发、预发布和生产环境的理论分离只是 MLOps 最佳实践的指南。然而,实际的实施可能会根据你的组织需求、工作流程和技术能力有显著差异。
在接下来的部分中,我们将深入探讨多种部署 Databricks 工作空间的方法,以便更好地将你的开发、预发布和生产环境与特定的组织需求对接。
下图展示了三种不同的部署模式,旨在有效地设置你的开发、质量保证和生产环境:
图 10.5 – 各种 Databricks 环境部署方式
注意
以下是前述图的来源:《MLOps 大全》。
让我们逐一了解这些模式。
在 Databricks 中导航环境隔离 – 多种 MLOps 策略
为了制定一个健壮的 MLOps 策略,你不仅需要考虑涉及的资源类型,还要考虑它们所在的环境——开发、预发布或生产。每个环境提供不同级别的可访问性、测试严格性和数据安全性,这些都受到组织规模、治理政策和安全要求的影响。
多个云账户
对于受严格规则和法规约束的大型组织,通常会将开发、预发布和生产环境分隔到不同的云账户中。在这种配置下,每个云账户将托管自己的 Databricks 工作区。该架构在云账户和网络级别上确保了隔离,但由于资源和数据存储的重复,可能会增加成本。
单一云账户与多个 Databricks 工作区
另外,较小的组织或项目可能会选择在一个云账户中包含多个 Databricks 工作区。每个工作区都部署在自己的网络中,并在该层级上实现隔离。虽然这种方式更具成本效益,但仍然能保证足够的隔离,并且能与组织的数据治理政策保持一致。
单一云账户与单一 Databricks 工作区
即便是在同一个云账户内,Databricks 也提供了严格隔离不同角色和项目的能力。像 RBAC、权限以及 Unity Catalog 等原生数据治理工具,使得在单一工作区内有效地进行访问隔离成为可能。
在探讨了多种组织 Databricks 开发、预发布和生产环境的方式后,是时候关注 MLOps 另一个关键方面:机器学习项目中生命周期的异步性。这与传统的软件 DevOps 有所不同,后者中的代码和应用更新通常是同步进行的。
以部署的大型语言模型(LLM)为例。这类模型的复杂性和规模使得重新训练成为一项艰巨的挑战。你可能会发现,尽管数据工程代码每月都会进行迭代,但模型本身的训练代码在长时间内保持静态。
另一方面,考虑一下一个 churn 预测模型。在这种情况下,可能会使用最新数据集每月安排自动重新训练。如果新训练的模型优于前一个模型,它会立即被迁移到生产环境中,而无需对现有代码库进行任何更改。
应对异步生命周期
鉴于机器学习模型和代码更新周期的不一致,采取管理这些异步性的方法变得至关重要。你可能会采用如金丝雀发布等技术以确保模型的安全发布,或选择蓝绿部署来确保更顺畅的回滚。自动化监控系统和警报机制同样重要,能够作为模型退化或操作问题的早期预警系统,从而实现快速修复。
财务和监管考虑事项
除了技术方面,MLOps 还涵盖了财务和合规变量。不能忽视成本考虑 – 包括数据存储和计算资源。此外,数据血统对于通过您的流水线跟踪数据移动至关重要,这不仅有助于调试,而且对于合规和审计目的至关重要。同样,数据版本控制在模型可重现性方面至关重要,尤其是对于频繁重新训练的模型而言。
通过这种微妙的理解,我们能更好地处理 ML 生命周期中异步更新带来的复杂性,特别是在 Databricks 或任何 MLOps 平台的背景下。
现在,让我们来看看你可以利用的各种 ML 部署范式。
理解 ML 部署模式
任何 ML 项目的最终目标是将我们的 ML 模型投入生产。根据我们正在服务的用例类型和我们的 ML 工程团队的复杂性,有两种广义的 ML 部署方法。
-
部署模型方法
-
部署代码方法
让我们逐个理解这些方法。
部署模型方法
模型部署工作流遵循结构化方法论,从开发环境开始,其中包括用于训练 ML 模型的代码的制定和完善。在模型经过训练并确定最佳版本之后,它将正式注册在专用模型注册表中。接着进行一系列集成测试以评估其性能和可靠性。成功通过这些评估后,模型首先升级到暂存环境进行进一步验证。一旦满足所有必要条件,它就会被部署到生产环境中。
以下图像展示了这种多阶段方法的图形化描述:
图 10.6 – 部署模型方法
注意
这是前述图像的来源:MLOps 大书。
在整本书中,迄今为止我们使用的所有笔记本都集中在这种特定的部署方法上。这是公司和团队特别是 ML 团队成员中,尤其是数据科学背景而非传统软件工程背景的人的流行选择。这种方法提供了简单性,并且是 ML 项目的一个很好的起点。
以下图像展示了部署模型方法的完整端到端 MLOps 生命周期:
图 10.7 – 使用部署模型方法从开发到生产部署模型的参考架构和工作流程
注意
前述图像由 Databricks 提供。
在这个 MLOps 工作流程中,数据工程师、数据科学家和 ML 工程师协作完成各种步骤,确保 ML 模型的成功开发、部署和监控。以下是每个角色的责任和任务分解:
-
数据工程师:
-
从各种来源收集数据,如数据库、云存储和传感器,确保数据的可靠性和质量。
-
清洗和预处理数据,处理如删除重复数据、处理缺失值,并将数据转换为适合 ML 算法的格式。
-
在数据仓库或 Delta Lake 中存储和管理数据,确保数据科学家和 ML 工程师可以高效利用和访问这些数据。
-
-
数据科学家:
-
探索和分析数据,深入了解其特征,识别相关的模式和关系。
-
生成并注册特征到特征表中以供重复使用。
-
开发和训练 ML 模型,采用各种算法和技术实现准确的预测和期望的结果。所有的模型运行和实验会自动记录到 Databricks 上的 MLflow 跟踪服务器中。
-
使用适当的度量标准和验证技术评估和评估训练模型的性能。
-
根据性能和业务需求选择最合适的模型进行部署。最佳模型将被注册到模型注册表中,作为候选模型。
-
-
ML 工程师:
-
将 ML 模型部署到生产环境中,使其能够实时进行预测或决策。
-
监控已部署模型的性能,确保其正常运行,并检测任何异常或行为漂移。
-
随着新数据的到来,更新和重新训练模型,保持模型的相关性和准确性。
-
本书中涵盖的所有笔记本都展示了这一工作流程。
现在我们已经了解了 MLOps 中模型部署方法的工作原理,接下来让我们看看部署代码的方法。
部署代码的方法
在部署代码的方法中,我们不仅对训练 ML 模型的代码进行版本控制,还对创建特征表的代码进行版本控制。当每个环境中对数据访问有严格规定时,这种方法非常有效。
数据科学家在开发环境中开发特征工程和模型训练的代码。在找到合适的候选模型后,开发分支代码被提交到暂存分支,在那里进行自动化单元测试。接着,我们在暂存环境中训练模型并进行性能基准测试。一旦一切正常,我们将代码推送到主分支和生产环境。在这里,我们再次在生产数据上重新训练模型:
图 10.8 – 从开发到生产部署模型的参考架构和工作流,使用部署代码方法
注释
这是前面图表的来源:《MLOps 大书》。
开发过程涉及几个阶段,从开发环境中为训练模型和特征工程创建代码开始。以下图展示了开发环境中部署代码工作流的逐步过程:
图 10.9 – 开发环境中的部署代码工作流
注释
由 Databricks 提供
让我们逐步了解这些步骤:
-
数据访问点:在开发环境中,数据科学家通常对生产数据具有只读权限。出于合规性原因,访问可能仅限于这些数据的已清洗或复制版本。还可以为读写操作提供单独的开发存储,以便进行实验性工作。
-
初步数据调查(PDI):数据科学家使用迭代、交互式方法进行数据探索,利用笔记本、可视化图表和 Databricks SQL。此步骤通常是独立的过程,通常不属于可部署的管道的一部分。
-
源代码管理:所有的机器学习系统代码都存储在版本控制库中。数据科学家在此 Git 库中的开发分支上工作。代码可以通过 Databricks Repos 与 Databricks 工作区进行同步。
-
增强特征数据集:此管道从原始和现有特征表中摄取数据,并将其输出到特征库中的表。这一步包括两个主要任务:
-
质量保证:在此,数据会被验证以确保其符合质量标准。
-
特征构建:数据科学家编写或更新代码以生成新的特征。数据可能来自特征库或其他湖仓表。这些开发特征表用于构建实验模型,推广到生产后,它们会更新相应的生产表。
如果特征管道由不同的团队管理,它们的管理可以是分开的。
-
-
模型训练管道:数据科学家在只读生产数据或特定于开发的数据上构建模型训练管道。这些管道可能利用来自开发和生产环境的特征表:
-
调优与训练:训练过程从特征库和不同层次的湖仓表中获取数据,同时在 MLflow 跟踪系统中记录参数、度量和工件。
-
模型存储:在训练和调优完成后,模型存储在 MLflow 跟踪服务器上,记录其与输入数据和代码的关联。
当在暂存或生产环境中执行时,模型可以被检索并注册以便进行持续管理和测试。
-
-
代码定稿:一旦特征、训练和推理的管道开发工作完成,无论是数据科学家还是 ML 工程师都会将这些更改提交到版本控制系统中的开发分支。
接下来,让我们了解一下预发布环境中的工作流程。预发布环境作为 ML 代码进入生产环境之前的最终测试场地,涵盖了所有管道组件的全面测试,包括模型训练和特征工程。ML 工程师利用 CI 管道执行单元测试和集成测试。测试成功后,生成发布分支,触发 CI/CD 系统启动生产阶段。
下图为您提供了预发布环境工作流程的逐步可视化指南:
图 10.10 – 预发布环境中的部署代码工作流程
注意
感谢 Databricks 的提供
让我们详细了解每个步骤:
-
启动合并过程:当 ML 工程师提交合并请求到源代码管理的预发布分支(通常是“main”分支)时,部署之旅开始。这一操作触发了 CI 工作流程。
-
执行单元测试:在 CI 框架中,源代码会自动编译并启动单元测试。如果这些测试未通过,合并请求将被拒绝。请注意,单元测试与数据或外部服务相互独立。
-
进行集成测试:在单元测试之后,CI 机制会执行集成测试。这些测试验证所有管道的兼容性和功能,包括特征工程、模型训练、推理和监控。预发布环境的设计尽可能接近生产环境。
为了节省测试时间,可以在测试的彻底性与执行速度之间做出妥协。例如,可以使用较小的数据子集,或者减少训练周期。根据模型的预期应用,可能会在此阶段进行全面的负载测试。
在预发布分支完成集成测试后,代码才有资格进行生产部署。
-
提交到预发布分支:如果测试成功,代码会合并到预发布分支。如果测试失败,CI/CD 系统会通知相关人员,并将测试结果更新到合并(或拉取)请求中。
可以定期安排集成测试,尤其是当预发布分支频繁收到多个贡献者的更新时。
-
建立发布分支:当代码经过验证并准备好进行生产部署时,ML 工程师创建发布分支。此操作促使 CI/CD 系统刷新生产任务。
最后,让我们了解一下生产环境的工作流程。
在生产环境中,ML 工程师监督处理特征计算、模型训练与测试、预测发布和性能监控的 ML 管道的部署。一个再训练机制在生产数据上运行,以保持模型的更新和优化。性能基准经过严格评估,以确保新模型符合或超过设定的标准。在这个环境中,数据科学家通常没有写入和计算权限,但可以查看测试结果、日志、模型工件和管道状态,以帮助诊断生产中的问题。
以下图表提供了生产环境中工作流程的全面逐步可视化:
图 10.11 – 生产环境中部署代码的工作流程
注意
感谢 Databricks 提供支持
让我们一步一步地了解这个工作流程:
-
刷新特征数据:此阶段涉及从生产环境摄取新数据并更新特征存储中的表格。此过程可以是批处理或实时处理,并且可以通过不同的触发器启动,例如定时任务或连续运行。
-
模型训练:
-
调优和训练:管道在完整数据上训练生产模型,并通过自动记录日志相关的度量和参数。与开发阶段不同,只有表现最佳的算法和超参数才会被考虑,以优化时间和性能。
-
模型评估:模型质量通过与生产环境中的独立数据集进行测试。测试结果和自定义度量被记录。
-
模型注册:在成功训练后,模型以“None”初始状态在模型注册表中注册。
-
-
自动化部署:
-
合规性验证:管道执行强制的合规性检查,可能包括复杂评估的人为审查。结果将被记录。
-
性能验证:在预发布阶段的模型与生产环境中的模型进行比较,以避免性能退化。
-
过渡到生产环境:模型在性能比较令人满意后,手动或自动地推进到生产阶段。
-
-
实时服务:MLflow 使模型能够部署到低延迟的用例中。部署的模型获取特征并为每个传入的请求返回预测结果。
-
批量或流式推理:对于更高的吞吐量或延迟要求,处理批量或流式推理。预测结果可以保存在各种存储选项中,包括消息队列,如 Apache Kafka。
-
持续监控:
-
数据喂送:从不同推理类型中摄取日志
-
性能和漂移度量:计算各种质量和性能度量
-
度量报告:度量结果被保存以供进一步分析和警报用途
-
-
重新训练触发器:模型可以根据时间表自动重新训练,或者根据性能下降触发重新训练。
注意
自动化重新训练过程可能会很复杂,并可能需要手动干预来解决通过监控发现的问题,例如数据漂移或性能下降。
下图总结了在不同环境中执行部署代码方法的 ModelOps 中的各种步骤:
图 10.12 – 在不同环境中执行部署代码方法的 ModelOps 中的各种步骤
注意
上述图由 Databricks 提供。
总体而言,您有三个环境。在顶部,您有 Git 工作流提供者,负责管理代码从一个环境到另一个环境的过渡。在底部,您有数据访问层或跨不同环境的特征表的数据。
在这里需要记住的重要一点是,训练好的模型本身将在生产环境的模型注册表中有其自己的阶段。我们会在每个环境中重新训练模型,并基于更新后的代码填充相应的特征表。
注意
这种方法可能更适合那些具有传统软件工程背景并熟悉 DevOps 原则的个人。然而,在撰写本书时,尚无正式建立的方法来使用目前普遍可用的工具在 Databricks 平台上实施 MLOps 的部署代码方法。虽然我们在本节讨论了部署代码方法的概念,但我们不会将其作为提供的代码的一部分来覆盖。
一旦 MLOps Stack 普遍可用,将解决此模型部署范式。一旦新功能可用,我们将更新本书。
现在,让我们总结本章并总结我们的关键学习内容。
摘要
在本章中,我们介绍了 MLOps 的基础知识,Databricks 上的不同部署方法及其参考架构。
选择模型部署方法应基于团队在实施机器学习项目的 DevOps 流程方面的熟练程度。重要的是要认识到,我们讨论的每种方法都有其各自的优缺点,因此不存在通用解决方案。然而,在 Databricks 环境中可以创建定制的混合 ModelOps 架构。
通过考虑团队的优势和专业知识,您可以确定最适合您项目的部署方法。评估可扩展性、可维护性、部署便捷性以及与现有基础设施的集成是至关重要的。评估这些方面将帮助您做出明智的决策,并优化模型部署过程。
在 Databricks 中,你可以根据项目需求灵活定制你的 ModelOps 架构。利用 Databricks 的功能,你可以结合不同部署方法的最佳元素,创造出一个定制化且高效的工作流。这种混合方法让你能够在利用不同方法的优势的同时,减轻它们的局限性。
记住,最终目标是建立一个强大且简化的模型部署流程,使其与团队能力和项目需求保持一致。通过仔细考虑你的选择并利用 Databricks 环境中的资源,你可以创建一个最大化效率和生产力的 ModelOps 架构,以支持你的机器学习项目。
进一步阅读
请查阅以下来源及其链接,以了解更多关于本章涵盖的主题:
-
MLOps 大书:bit.ly/big-book-of-mlops
-
MLOps 堆栈 在 GitHub:
github.com/databricks/mlops-stack
-
Damji, J. S., Wenig, B., Das, T., 和 Lee, D. (2020). Learning Spark(第二版)