数据科学家 Emily Gorcenski 谈数据版本控制(CD4ML)

简介: 将机器学习/人工智能/数据科学生产化是一项挑战。不仅机器学习算法的输出经常编译需要整合到现有生产服务中的制品,而且用于开发这些模型的语言和技术通常与构建实际服务时使用的语言和技术大不相同。

将机器学习/人工智能/数据科学生产化是一项挑战。

不仅机器学习算法的输出经常编译需要整合到现有生产服务中的制品,而且用于开发这些模型的语言和技术通常与构建实际服务时使用的语言和技术大不相同。

在这篇文章中,我想探讨独立自主的版本控制机器学习系统如何带来独特的挑战。 我将确定机器学习系统具有版本概念的四个关键轴,以及一些关于如何简化这一概念的简短建议。


将智能加入栈


考虑以下一种场景:您在基于 JVM 的栈上运行大型 Web 服务,现在您想要合并机器学习模型。你有数据科学家,他们已经花了一些时间进行研究,现在他们已经准备好交付他们的工作产品:一个用 R 构建的概念验证模型,你必须以某种方式实现它,并以某种方式维护它(当您的数据科学家都不是后端工程师并且您的后端工程师都不会 R 时)。

在现代软件工程环境中,关于应用数据科学有许多悬而未决的问题:

  • 我们如何测试包含机器学习的应用程序?
  • 我们如何处理用户体验?
  • 我们如何应用 DevOps 和持续交付等原则?
  • 我们如何使黑盒制品的文档保持最新?
  • 等等

这些问题中的大多数都没有一个公认的答案,就像我们在应用程序开发领域所接受的答案一样。即使是大型科技公司也在这里磕磕绊绊。这里有很多讨论,但我想在这篇文章中关注一个问题的一个要素:我们如何通过数据科学实现持续交付?我不会在这篇文章中详细介绍持续交付的所有细节,但我会指出机器学习应用程序经常遇到的几个关键原则:持续改进的要求,以及能够回滚到要求任何时间点的任何发布。为了理解原因,我想重点介绍机器学习应用程序确定性应用程序的区别。

当我们构建标准服务和软件(我称之为确定性)时,我们就有了版本的概念。我们构建软件,它实现功能并具有下游和上游的依赖关系,它执行一些任务。对于给定的功能集和更改历史,我们根据某种方案为该软件分配一个版本(该方案其实并不重要,有些方案比其他方案更好)。当我们更改代码时,我们就更改了版本。如果我们需要回滚软件,我们可以回滚到源代码的前一个版本,并重新构建和部署。这是基本原则,尽管它并不总是像我在这里说的那么简单。

当谈到机器学习应用程序时,我们遇到了一个大问题。主要的制品通常是一个编译模型,它可能非常大,并且没有任何类似于服务架构、依赖关系或其他任何东西的概念。它本质上是一个带有输入和输出的逻辑球。在这个制品中编码了几个假设:它继承了训练它的数据集的形状和类型;它继承了训练它的数据集的分布函数(我喜欢称之为宇宙状态);它通常依赖于创建它的代码或框架。

换句话说,机器学习系统是模型+数据+代码。他们每一个都可能而且确实会改变。让我们看看这些变化是如何发生的。


理解模型

许多数据科学入门书和文章将模型视为机器学习方法的产物,或者有时是其工作的抽象方法,但我认为这过于具体和限制性。让我们换个角度看,请允许我谈一谈形而上学。

宇宙以某种方式作用于数据。有输入,这些输入被一个过程修改,从而产生输出。该过程可以是一些物理描述,例如:它可能是随机的(例如原子的衰变);它可能是无法发现的,甚至是任意的,也无法完全解释,例如:无论您选择白酱还是红酱作为意大利面晚餐。宇宙是对自身的唯一完美模拟,但我们并不要求完美。毕竟,我们不需要广义相对论来知道开车时何时踩刹车。

模型是给定过程的近似值。模型在其域(可能输入的空间)和范围(可能输出的空间)中都受到限制。我们的目标是确定一个模型,该模型在我们关心的领域内提供合适的近似值,其准确度水平可以很好地描述宇宙的实际运作方式。


在构建模型时,我们通常希望从简单开始。许多问题可以通过线性或逻辑回归算法来解决。当你第一次将机器学习应用于一个问题时,你最大的改进通常来自于实现任何解决方案,而不一定是最优的解决方案(改天的主题是模型复杂性的收益递减)。在这种情况下,我认为模型是超参数和算法方法的组合,而不是参数(取决于数据,下面讨论)。

也就是说,持续改进的原则告诉我们,我们不应该停留在这里。最终,我们可能希望提高我们的准确性。或者适用范围可能会改变。因此,我们的模型必须改变。我们可以通过对新数据进行再训练来做到这一点,但最终给定的建模方法可能不再适用。在某些时候,我们可能会摆脱逻辑回归并决定使用随机森林或神经网络。

此外,我们可以对相同的数据应用不同的建模方法来比较性能。逻辑回归和神经网络可能具有相似的准确度行为,但其中一个可能在另一个难以解决的问题域中表现出色。

不同的建模方法具有不同的属性和局限性。逻辑回归是高度可解释的,但神经网络不是。因此,当我们考虑我们的系统会影响哪些下游需求时,我们对模型的选择可能会产生与版本相关的影响,这些影响与用于训练它们的数据无关。出于这个原因,模型的选择(包括它的超参数),应该被认为是一个版本轴


理解数据

在探索机器学习版本如何波动时,数据是非常相关的。事实上,它是如此重要,以至于我将其分解为两个独立的、同样重要的子类别:schema和值。

如果我们承认上一节中描述的形而上学隐喻,那么数据就是对宇宙状态的测量或评估。数据有许多重要的属性,但我们最关心的两个是它的形状和分布。形状可以被认为是一种schema,即描述数据所在空间属性及其值的结构化方式,即它在该空间中分布的方式

了解值如何变化

数据变化。宇宙的真相发生了变化。经济起起落落,我们的用户群会增长或变老。趋势变化。技术变化。因此,没有理由期望我们的数据看起来总是一样的,即使它的基本形状保持不变。我们必须始终重新训练我们的模型。

这是一个容易理解的问题,但在持续交付的世界中实现起来却更加困难。毕竟,如果我们需要能够回滚到任意时间点,那么我们需要能够在任何给定时间点对我们训练模型的数据进行版本控制。这在数据驱动的应用程序中可能比在软件应用程序中更紧迫。在软件方面,我们总是希望不断前进,但非确定性系统,例如:AI 应用程序,却极难有效修补。

其他数据问题可能比比皆是。有时,由于软件错误,可能会错误地记录数据。欺诈行为可能会破坏数据。这些事情需要时间来捕捉,有时它们无法追溯补救。出于这个原因,应该清楚的是,我们需要能够在数据上重新训练模型,因为它反映在过去的任何时候,因此,我们应该将数据集的实际值视为版本轴


了解 Schema

数据 schemas 也存在类似的数据问题。我们可以将 schema 视为数据的“形状”(例如:关系数据库 schema),当我们从数据中派生制品时,我们通常会继承该 schema 的一些属性。例如,假设您有一个表示状态的字段。这是什么?这是一个字符串吗?这有子字段吗?

Schema 的变化很烦人,因为太多依赖于它们:对象模型、数据库表、XML 有效负载等。机器学习制品也可以依赖于 schema;例如,如果机器学习算法需要一个status字段,那么如果将来某个时间该字段变为 status_membership 和 status_editor,它就会崩溃。

数据schema可以独立于数据而改变。第三方服务可以开始提供带有额外字段的 JSON 有效负载。非标准化字段可以在不改变数据值的情况下重新标准化。回滚 schema 更改非常困难。但这并不总是可以避免的。数据 schema 代表版本轴,因为它们与上游和下游依赖项紧密耦合。


理解代码

在机器学习系统的所有组件中,代码可能是技术人员最了解的,因为我们一直致力于构建确定性软件系统,并且在这种情况下持续交付原则得到了很好的理解。

对于机器学习系统,我们可以将代码分解为实现代码和模型开发代码。 我们还可以探索基础设施即代码,这也是这方面的相关概念。 认为代码代表版本轴的理由很清楚。但这里我们也指出,在实践中,大多数编译的机器学习制品都有代码依赖关系,因此,维护依赖关系与维护模型一样重要。


解决机器学习版本的挑战

假设您已经做到了这一点,并且大体上同意通过将智能放入生产栈中,我们显著地使维护版本的概念复杂化。我们介绍了四个主轴:模型、值、schema和代码。机器学习系统可以沿着这四个轴独立地改变。

有一些广泛的方法来应对这一挑战,我将在这里介绍其中的一些。


将模型视为代码

一种方法是将模型/建模方法视为代码。由于我们通常使用一些 python 或 R 脚本等来构建模型,同时使用一些库/依赖项,如 Tensorflow,我们可以简单地将模型视为我们正在使用的代码的扩展。

好处

这是一种明智的方法,因为我们可以在master上开发,同时进行其他开发,任何回滚都会自动包括对模型早期版本的回滚。这会通过将两个逻辑上不同的概念锁定在一起,从而消除一定程度的自由度。这也意味着您的数据科学家不是在孤岛中工作,而是完全集成到一个跨职能团队中

挑战

这种方法的挑战之一是它没有考虑建模方法如何与机器学习系统的其他元素相关联,因此,它将所有其余代码与数据和 schema 耦合,这可能会独立漂移。这可能是一个很大的挑战,也可能不是。

注意事项


如果你将模型和代码结合起来,那么它会使研究变得更加困难,这意味着进行实验工作以改进产品的数据科学家将需要在开发高峰期工作,或者你需要一个更复杂的特征标记系统来在构建过程中处理多个(大)制品。最终,由于模型是超参数和算法方法的结合,随着时间的推移,我们可能会发现自己周期性地恢复到“旧”解决方案,当所有其余代码继续前进时,这可能会感到奇怪。

建议


我建议将模型视为代码,原因与我们将基础设施视为代码相同。尽管它带来了一些挑战,但这是将两个密切相关的概念联系起来的自然方式,并且根据我的经验,负面影响是微乎其微的。

连接 Schemas 和值

这种方法也很自然。在处理数据时,我们只是将其作为 blob 存储在某处。无论如何,这些值可用于派生模式,因此这是有道理的。


好处

这可能是最容易实现的。我们可以简单地在每个训练周期转储一个表,在某个地方保存一个训练表,使用具有时间依赖性的数据集市/物化视图/存储查询,或任何其他技术解决方案。此外,如果我们将值和 Schemas 联系起来,我们就可以非常清楚地了解数据在任何给定点代表什么。这意味着我们不必估算缺失值或编写复杂的适配器/接口来将旧数据压缩成新的形状,反之亦然,这种方法很快就会变得复杂且难以置信。它还使我们不必猜测新添加字段的默认值是什么。


挑战

首先,这比仅在给定时间点转储数据要复杂一些。这更加依赖于对我们的Schemas进行编码并将其与数据保持联系的工具。此外,处理 schema 更改可能一点也不难。但更关键的是,如果我们将值和 schema 联系起来,如果我们的 schema 发生变化,那么当 schema 发生变化时,我们基本上是从头开始,除非我们弄清楚如何将数据从旧 schema 转换为新 schema 。做过数据迁移的人都知道,这并不总是那么容易。

首先,这比在给定时间点转储数据要复杂一些。这使得我们更加依赖于工具来编码我们的 Schemas,并将其与数据联系起来。此外,处理 Schemas 更改可能一点也不困难。但更关键的是,如果我们将值和 Schemas 联系起来,如果我们的Schemas发生了变化,那么当Schemas发生变化时,我们基本上是从零开始的,除非我们弄清楚如何将数据从旧 Schemas 转换为新 Schemas 。任何做过数据迁移的人都知道,这并不总是容易的。


建议

我不建议连接值和 Schemas。将值简单地转储到 CSV 文件或类似文件通常更容易,并且我们可以根据需要推断Schemas或在其他地方记录它们。对于新列之类的东西,有时可以使用统计方法来插补值。如果数据的形状发生变化,编写适配器有时并不难,但请考虑您的场景。如果它涉及重大迁移或频繁更改,最好将所有内容链接到您的 Schemas 并根据需要进行调整。


使用数据版本控制链接数据和代码

这种方法被 dvc 等工具使用。简而言之,我们将数据发送到某个存储解决方案,以有意义的方式对数据进行哈希处理,然后编写一个小存根,我们可以将它与我们的代码一起提交到源代码控制。

好处

这种方法越来越受欢迎,MLFlow、Pachyderm 和 dvc 等工具提供了实现这一目标的功能。这使得共享和重复工作变得更加容易,并保证训练和验证数据始终相同。存储相当便宜,其中,许多工具与现有的源代码控制工具很好地集成在一起


挑战

这可能会占用大量存储空间,因为我们可能会一遍又一遍地复制相同的数据。这也不一定适用于所有类型的数据。用于此的工具仍然不完全成熟。

建议

鉴于您的数据存储和访问解决方案,我建议您尽可能最好地实现这一点。即使数据存在于 HDFS 上,我们也可以对文件路径数组进行版本控制,并保留对其的引用。对于 blob 数据,我们可以使用正在开发的任何这些工具创建经过散列和控制的数据集。


从代码中取消链接数据/模型

我采用的另一种方法是简单地将模型或数据与其余实现代码断开链接。 在这种方法中,就模型发布周期达成一致,例如:每周一次。 一个新的训练和验证数据集被派生出来,放在一边,并且训练一个或多个新模型。 然后在需要使用它的任何服务中实现。


挑战

这不是持续交付,会导致您的数据科学家在孤岛中工作。

建议

不要这样做。 这样做是解决棘手的集成问题的好方法。

限制建模方法

使用此解决方案,您基本上选择了一种建模方法并承诺使用它。您可以更改超参数,并且您肯定会重新训练模型,但您不会更改算法方法,甚至可能实现您自己的代码


好处


这并不像听起来那么愚蠢。大多数时候,我们只需要一个基本的方法。通过专注于研究一种技术,就有可能成为它可能遇到的所有各种问题的专家。它允许您专门化您的支持代码(例如:训练和验证代码、实现代码),并且它使调整和优化变得更加容易。

挑战

如果你唯一的工具是一个随机的森林形状的锤子,那么每个问题都最好是一个随机的森林形状的钉子。它在你的代码中对方法、工具等产生了很多依赖,使得以后很难改变。这确实是第一个可能的解决方案的超特定方式(即链接模型和代码)。

建议

如果您有大规模问题,并且需要能够定期测试和部署多个模型,那么这是一个很好的方法。如果你有简单的问题,并且不想追求最新的闪亮技术,这也很好。更广泛地说,我认为大多数应用程序都应该向各种可能的建模方法敞开大门,并保持在这些界限之内。

总结

数据科学很难生产化,原因之一是它有太多的活动部件。 智能/AI/机器学习应用程序的“版本”的概念(至少)有四个可能的轴,它可以在上面漂移,这对持续交付实践提出了挑战。 这些挑战是可以解决的,但我看到人们在实践中尝试解决这些问题的各种方式各有利弊。

最后,关注持续交付原则很重要。 我们应该努力将数据科学家整合到我们的交付团队中,让开发人员参与数据科学工作,并将机器学习视为功能软件,而不是神奇的黑匣子


相关文章
|
6月前
|
机器学习/深度学习 人工智能 开发工具
人工智能项目的python版本管理工具DVC
dvc即data version control, 是一种针对人工智能项目(机器学习或者深度学习)的数据版本管理工具。DVC的操作和GIT类似,可以认为为GIT的二次开发封装。结合GIT,DVC可以有效的管理人工智能项目的整个流程,包括代码,数据,训练配置,模型【2月更文挑战第12天】
78324 1
|
24天前
|
运维 监控 jenkins
运维自动化实战:利用Jenkins构建高效CI/CD流程
【10月更文挑战第18天】运维自动化实战:利用Jenkins构建高效CI/CD流程
|
3月前
|
机器学习/深度学习 测试技术 持续交付
ONNX 与持续集成/持续部署 (CI/CD):构建可信赖的 ML 生命周期管理
【8月更文第27天】随着机器学习 (ML) 模型的广泛应用,确保模型的正确性、稳定性和可追踪性变得尤为重要。持续集成/持续部署 (CI/CD) 是软件开发中的重要实践,旨在通过自动化测试和部署流程来提高软件质量和开发效率。将 ONNX 集成到 CI/CD 流程中可以实现模型版本管理、自动化测试和部署,从而构建一个可信赖的机器学习生命周期管理系统。本文将探讨如何将 ONNX 模型与 CI/CD 流程结合,以实现模型的自动化管理。
74 5
|
6月前
|
监控 安全 搜索推荐
团队对CI/CD 工具的要求
选择和评估CI/CD工具的关键点包括:易用性和可定制性,需兼顾新手友好与团队个性化需求;强大的自动化能力,能处理复杂流程;良好的集成性,与各类开发工具无缝配合;开源和成本效益,开源选项常受青睐以降低成本;丰富的文档和社区支持,便于问题解决和功能利用;重视安全性,保护代码和部署安全;具备可扩展性,随团队及项目规模增长而扩展;以及提供监控和报告功能,确保及时响应构建、测试和部署的状态。这些因素有助于提升软件开发效率和质量。
87 0
|
6月前
|
存储 Linux 开发工具
深入了解Git LFS:高效管理大型文件的利器
Git LFS是Git的一个扩展,旨在更有效地处理大型文件。它通过将大文件存储在单独的位置,而在Git仓库中只保留引用和元数据,来减小仓库的体积。这使得Git仓库能够更快速地克隆、推送和拉取,同时有效地处理大型媒体文件、二进制文件等。
409 1
深入了解Git LFS:高效管理大型文件的利器
|
机器学习/深度学习 存储 监控
DVC 使用案例(三):机器学习持续集成与持续交互( CI/CD )
将 DevOps 方法应用于机器学习 (MLOps) 和数据管理 (DataOps) 越来越普遍。对于一个完善的 MLOps 平台来说,需要囊括资源编排(为模型训练提供服务器)、模型测试(验证模型推理)、模型部署到生产,以及模型监控和反馈等机器学习生命周期各个环节。 DVC 可以管理数据/模型和重现 ML 流水线,而 CML 可以协助编排、测试以及监控。
|
SQL 机器学习/深度学习 安全
将DAST集成到CI/CD管道中的优势和实施步骤
将DAST集成到CI/CD管道中的优势和实施步骤
161 0
|
存储 机器学习/深度学习 SQL
「机器学习」DVC:面向机器学习项目的开源版本控制系统
「机器学习」DVC:面向机器学习项目的开源版本控制系统
|
存储 前端开发 jenkins
实践:部署Jenkins服务并开发MERN应用的CI/CD构建管道
为了解决这个问题,我们可以创建一个 CI/CD流水线。因此,每当您添加功能或修复错误时,都会触发此管道。这会自动执行从测试到部署的所有步骤。
280 0