为解决机器学习可复现性的问题,很多人会用 Git 和 Git-LFS,但这二者并不足以解决这个难题。为此,作者在文中提出了 DVC 并列出了它的三大优势:精准记录时间点和使用的文件、特定时间点使用命令的确切顺序、轻松实现数据和代码共享。
有人认为,由于软件工具的不充分,无法保证完全复现机器学习模型的结果,机器学习领域正「陷入危机」。这个危机可以通过为机器学习从业者提供更好的软件工具来解决。
可复现性问题非常重要,每年一度的 NeurIPS 会议也将其列为 NeurIPS 2019 讨论的主要议题。
所谓的危机是因为研究者难以复现同行或科学家们的工作,这制约了他们在彼此工作基础上进一步取得进展。由于机器学习和其他形式的人工智能软件在学术和企业研究中得到广泛应用,因此可复制性或可复现性是一个亟待解决的关键问题。
我们可能认为这可以通过典型的软件工程工具来解决,因为机器学习开发与普通软件工程类似。在这两种情况下,我们会生成某种编译软件工具,以便在计算机硬件上执行,并获得准确的结果。为什么我们不能利用丰富的软件工具和质量极佳的软件来为机器学习团队构建可复现流程呢?
遗憾的是,传统的软件工程工具并不能很好地满足机器学习研究者的需求。
关键问题是训练数据。通常,训练机器学习模型需要大量的数据,例如图像、视频或文本。而训练数据不在任何一种源代码控制机制下,因为像 Git 这样的系统不能很好地处理大型数据文件,并且用于生成 delta 文本文件的源代码控制管理系统不能很好地处理对大型二进制文件的更改。
任何经验丰富的软件工程师都会告诉你,没有源代码控制的团队只是「无头苍蝇」。更改文件不会一直被记录,团队成员时常会忘记执行过的操作。
而当训练结束时,你可能无法复现用该训练数据训练的模型,因为训练数据集将以未知方式发生改变。如果没有软件系统记录某次的数据集状态,那么有什么机制可以记录这一切呢?
Git-LFS 是解决方案吗?
我们首先想到的解决方案可能是简单地使用 Git-LFS (Git Large File Storage),顾名思义,它在构建 Git 时处理大文件。Git-LFS「用 Git 内部的文本指针替换大型文件,如音频、视频、数据集和图形,同时将文件内容存储在 GitHub.com 或 GitHub Enterprise 等远程服务器上。」
我仿佛还能听到机器学习团队说「听起来很棒,开始吧」。它能够处理数千兆字节的文件,加快远程存储库的出库速度,并使用同样舒适的工作流。这肯定符合标准了,对吧?
并没这么简单,项目经理没有告诉你要三思而后行吗?就像另一个宝贵的人生意见一样:过马路之前要左右看看。
你应该首先考虑的是 Git-LFS 需要一个 LFS 服务器,并且该服务器不是通过每个 Git 托管服务都可用。三巨头(Github、Gitlab 和 Atlassian)都支持 Git-LFS,但也许你天生爱 DIY。相比使用第三方 Git 托管服务,你可能更愿意自己托管 Git 服务。例如,Gogs 是一个功能强大的 Git 服务器,你可以轻松地在自己的硬件上运行,但它没有内置的 Git-LFS 支持。
根据你的数据需求,下一步可能会有点「致命」:Git-LFS 允许的存储文件最大为 2 GB。这是 Github 带来的限制,而非 Git-LFS,但是似乎所有的 Git-LFS 实现都受到各种限制。Gitlab 和 Atlassian 都有各种 Git-LFS 限制。想想 Github 的这个 2GB 限制:Git-LFS 有个应用案例是存储视频文件,但是视频的大小经常超过 2GB。因此,Github 上的 GIt-LFS 可能不适用于机器学习数据集。
不仅仅是 2GB 的限制,Github 对 Git-LFS 使用的免费层也设置了严格的限制,使用者必须购买涵盖数据和带宽使用的数据计划。
与带宽相关的一个问题是,当你使用托管的 Git-LFS 解决方案时,训练数据会存储在远程服务器中,必须通过 Internet 下载数据。而下载过程严重影响用户体验。
另一个问题是,在运行基于云的 AI 软件时,通常需要将数据文件放置在云存储系统(AWS、GCP 等)上。而来自 Git 服务器三巨头的主要 Git-LFS 产品将 LFS 文件存储在它们的服务器上,一般不支持云存储。
有一个 DIY 的 Git-LFS 服务器可以在 AWS S3 上存储文件,网址是 https://github.com/meltingice/git-lfs-s3,但是设置自定义的 Git-LFS 服务器需要额外的工作。
而且,如果需要将文件放在 GCP 而不是 AWS 基础架构上时,该怎么办?是否有 Git-LFS 服务器能够将数据存储在自主选择的云存储平台上?是否有使用简易 SSH 服务器的 Git-LFS 服务器?换句话说,GIt-LFS 限制了用户对数据存储位置的选择。
使用 Git-LFS 解决了所谓的机器学习复现危机吗?
使用 Git-LFS 后,你的机器学习团队可以更好地控制数据,因为它现在是版本控制的。这是否意味着问题已解决?
先前我们说过「关键问题是训练数据」,但这是一个小谎言。是的,数据能在版本控制下就是一个很大的改进。但是缺乏对数据文件的版本控制是整个问题所在 吗?并不。
什么决定了训练模型或其他活动的结果?决定因素包括但不限以下内容:
训练数据——训练模型时使用的图像数据库或任何数据源
训练模型使用的脚本
训练脚本使用的库
处理数据使用的脚本
处理数据使用的库或其它工具
操作系统和 CPU/GPU 硬件
生产系统代码
生产系统代码使用的库
显然,训练模型的结果取决于各种条件。由于存在多方变量,所以很难准确描述,但一般的问题是缺少所谓的配置管理。软件工程师已经认识到能够指定部署系统时使用的精确系统配置十分重要。
机器学习可复现性的解决方案
人类是一个富有创造力的群体,为这个「危机」提出了很多可能的解决方案。
R Studio 或 Jupyter Notebook 等环境提供了一种交互式 Markdown 文档,可以配置用来执行数据科学或机器学习工作流。这对于记录机器学习工作以及指定使用哪些脚本和库来说非常有用。但是这些系统不提供管理数据集的解决方案。
同样,Makefile 和类似的工作流脚本工具提供了一种重复执行一系列命令的方法。执行命令是通过文件系统时间戳确定的。这些工具也不提供数据管理解决方案。
另一方面,像 Domino Data Labs 或 C3 IoT 这样的公司提供了数据科学和机器学习的托管平台。两者都将基于大量数据科学工具的产品打包在一起。在某些情况下,如 C3 IoT,用户使用专用语言编码,并将数据存储在专用数据存储中。「一站式备齐」可能真的很便捷,但它能提供足够的灵活性吗?
本文接下来的部分将介绍 DVC。它的设计充分利用了大多数人对 Git 的熟悉程度,旨在与 Git 功能紧密匹配,但它具有适用于机器学习环境中的工作流和数据管理的功能。
与 Git-LFS 或其他几种可能的解决方案相比,DVC 承担并解决了机器学习复现性的大部分问题。它的方式是在 DVC 和像 Git 这样的源代码管理系统(SCM)中混合管理代码(脚本和程序)以及大数据文件。此外,DVC 管理处理机器学习实验中使用的文件所需的工作流。
DVC 文件中描述了数据文件和要执行的命令,我们将在接下来的小节介绍这些文件。最后,使用 DVC 可以轻松地将数据存储在许多存储系统上,像本地磁盘、SSH 服务器或云系统(S3、GCP 等)。DVC 管理的数据可以很容易地与其他使用此存储系统的用户共享。
DVC 使用与 Git 类似的命令结构。正如我们看到的,就像 git push 和 git pull 用于共享代码和配置一样,dvc push 和 dvc pull 用于共享数据。所有这些都将在后面的章节详细介绍,或者如果你想学习 DVC,请参阅教程:https://dvc.org/doc/tutorial。
DVC 可以精准记录时间点和使用的文件
DVC 的核心是为存储和版本控制大文件而优化的数据存储(DVC 缓存)。团队可以选择将哪些文件存储在 SCM(如 Git)中,哪些存储在 DVC 中。存储由 DVC 管理的文件,这样 DVC 可以维护每个文件的多个版本,并使用文件系统链接快速更换正在使用的文件版本。
从概念上讲,SCM(如 Git)和 DVC 都有存储库,其中包含每个文件的多个版本。如果查看「版本 N」,相应的文件将出现在工作目录中,然后查看「版本 N + 1」,文件将会匹配新版本。
在 DVC 端,这在 DVC 缓存中处理。存储在缓存中的文件通过内容校验和(MD5 哈希值)进行索引。随着 DVC 管理的各个文件发生变化时,其校验和会发生变化,并会创建相应的缓存条目。缓存将保存每个文件的所有实例。
为了提高效率,DVC 使用多种链接方法(取决于文件系统支持)将文件插入工作区而无需复制。这样,DVC 可以在请求时快速更新工作目录。
DVC 使用所谓的「DVC 文件」来描述数据文件和工作流步骤。每个工作区将有多个 DVC 文件,每个文件都用相应的校验和描述一个或多个数据文件,每个文件都要描述在工作流中执行的命令。
cmd: python src/prepare.py data/data.xml
deps:
- md5: b4801c88a83f3bf5024c19a942993a48
path: src/prepare.py
- md5: a304afb96060aad90176268345e10355
path: data/data.xml
md5: c3a73109be6c186b9d72e714bcedaddb
outs:
- cache: true
md5: 6836f797f3924fb46fcfd6b9f6aa6416.dir
metric: false
path: data/prepared
wdir: .
示例的 DVC 文件来自 DVC 入门示例(https://github.com/iterative/example-get-started),并显示了工作流的初始步骤。在下一节,我们会详细介绍工作流。现在,请注意此命令有两个依赖项 src/prepare.py 和 data/data.xml,以及一个名为 data/prepared 的输出数据目录。这些都会产生 MD5 哈希值,并且随着文件更改,MD5 哈希值将发生变化,更改后的数据文件的新实例将存储在 DVC 缓存中。
DVC 文件被检入 SCM 管理(Git)存储库。当存入 SCM 存储库时,每个 DVC 文件都会使用每个文件的新校验和来更新(如果适用)。因此,使用 DVC 可以精确地重新创建每个提交的数据集,团队也可以精确地重新创建项目的每个开发步骤。
DVC 文件类似于 Git-LFS 中使用的「指针」文件。
DVC 团队建议在每个实验中使用不同的 SCM 标签或分支。因此,访问适合该实验的数据文件、代码和配置就像切换分支一样简单。SCM 将自动更新代码和配置文件,DVC 将自动更新数据文件。
这意味着你不用再绞尽脑汁去记住哪些数据文件用于什么实验了。DVC 会为追踪这一切。
DVC 会记住特定时间点使用命令的确切顺序
DVC 文件不仅能记住特定执行阶段使用的文件,还能记住在该阶段执行的命令。
复现机器学习结果不仅需要使用相同的数据文件,而且需要相同的处理步骤和相同的代码/配置。一般创建模型的步骤,首先要准备在后续步骤中使用的样本数据。你可能会利用 Python 脚本 prepare.py 来拆分数据,并且在 data/data.xml 文件中输入数据。
$ dvc run -d data/data.xml -d code/prepare.py \
-o data/prepared \
python code/prepare.py
我们用该语句使 DVC 记录该处理步骤。DVC「run」命令根据命令行选项创建 DVC 文件。
-d 选项定义依赖项,在本例中,我们看到 XML 格式的输入文件以及 Python 脚本。-o 选项记录输出文件,这里列出了输出数据目录。最后,执行的命令是一个 Python 脚本。
因此,我们输入的数据、代码和配置以及输出数据,都被事无巨细地记录在生成的 DVC 文件中,该文件对应上一节中显示的 DVC 文件。
如果 prepare.py 从本次提交更改为下一次提交,则 SCM 将自动跟踪更改。同样,对 data.xml 的任何更改都会在 DVC 缓存中产生新实例,DVC 将自动跟踪该实例。如果结果数据目录发生更改,DVC 也会跟踪它们。
DVC 文件也可以简单地引用文件,如下所示:
md5: 99775a801a1553aae41358eafc2759a9
outs:
- cache: true
md5: ce68b98d82545628782c66192c96f2d2
metric: false
path: data/Posts.xml.zip
persist: false
wdir: ..
这是 dvc add file 命令得到的结果,该命令仅在只有一个数据文件时使用,并且其他命令不会产生这个结果。例如,在 https://dvc.org/doc/tutorial/define-ml-pipeline 中会显示,结果会立刻出现在前面的 DVC 文件:
$ wget -P data https://dvc.org/s3/so/100K/Posts.xml.zip
$ dvc add data/Posts.xml.zip
然后,Posts.xml.zip 文件是本教程中一系列步骤的数据源,每一步都要从这些数据中获取信息。
退一步讲,我们要明确这些是更大型工作流中的单个步骤,或者在 DVC 中称之为管道的步骤。通过 dvc add 和 dvc run,可以将多个阶段串联起来,每个阶段都使用 dvc run 命令创建,且由 DVC 文件描述。
这意味着每个工作目录将包含多个 DVC 文件,其中一个用于该项目流程的每个阶段。DVC 扫描 DVC 文件,构建复现流程所需命令的有向非循环图(Directed Acyclic Graph DAG)。
每个阶段都像一个 mini-Makefile,只有当依赖关系发生变化时,DVC 才会执行命令。它也有所不同,因为 DVC 不会像 Make 那样只考虑文件系统时间戳,而是考虑文件内容是否已更改,这由 DVC 文件中的校验和与文件的当前状态确定。
最重要的是,这意味着不需再费尽周章记住每个实验使用哪个版本的脚本。DVC 会跟踪所有内容。
DVC 使团队成员之间轻松实现数据和代码共享
机器学习研究人员可能需要与同事合作,需要共享数据、代码和配置。或者需要将数据部署到远程系统,例如在云计算系统(AWS、GCP 等)上运行软件,这意味着将数据需要上传到相应的云存储服务(S3、GCP 等)上。
DVC 工作空间的代码和配置端存储在 SCM 中(如 Git)。使用普通的 SCM 命令(如 git5 clone),你可以轻松地与同事共享代码和配置。但是如何与同事共享数据呢?
DVC 具有远程存储的概念。DVC 工作空间可以将数据传输到远程存储中或从远程存储中提取数据。远程存储池可以存在于任何云存储平台(S3、GCP 等)以及 SSH 服务器上。
因此,要与同事共享代码、配置和数据,首先要定义远程存储池。保存远程存储定义的配置文件由 SCM 跟踪。接下来,将 SCM 存储库传送到共享服务器,该服务器附带 DVC 配置文件。当你的同事克隆存储库时,他们就可以立即从远程缓存中提取数据。
这意味着你的同事不用再费心思量如何运行你的代码。他们可以轻松复现你的确切步骤,充分利用精确数据来生成结果。
结论
复现结果的关键是,不仅要确保数据的正确版本,还要保证代码和配置文件的正确版本,并自动执行各个步骤。成功的项目有时需要与同事协作,而这可以通过云存储系统更轻松地实现。有些工作要求在云计算平台上运行 AI 软件,因此需要将数据文件存储在云存储平台上。
借助 DVC,机器学习研究团队可以确保他们的数据、配置和代码全部同步。它是一个易于使用的系统,可以有效地管理共享数据存储库和 SCM 系统(如 Git),以存储配置和代码。