在 GitHub 上编辑

教程:数据与模型版本控制

本示例的目标是让你亲身体验一个基本的机器学习版本控制场景:使用 DVC 管理多个数据集和 ML 模型。我们将使用 教程,该教程由 François Chollet 编写,用于展示如何利用一个非常小的数据集构建一个强大的图像分类器。 cats and dogs 用于分类猫和狗的数据集

我们强烈建议您阅读 François 的原始教程。这是一个绝佳的示例,展示了如何利用通用的预训练模型,在资源极其有限的情况下构建出高性能的新模型。

我们首先使用 1000 张带标签的图像训练一个分类模型,然后将图像数量翻倍(2000 张)并重新训练模型。我们会记录下这两个数据集以及对应的模型结果,并演示如何使用 dvc checkout 在不同 工作区 版本之间切换。

用于训练和验证分类器的具体算法并不重要,也不需要事先掌握 Keras 的知识。我们将把原始博客文章中的 脚本 当作一个黑箱来复用——它接收一些数据并生成一个模型文件。

准备工作

本教程最近一次测试使用的是 Python 3.7。

运行本教程中的命令需要安装 Git。此外,如果尚未安装 DVC,请按照这些说明安装 DVC

请参阅 在 Windows 上运行 DVC 以获取提升 Windows 使用体验的重要提示。

好了!让我们先下载代码并设置一个 Git 仓库:

$ git clone https://github.com/iterative/example-versioning.git
$ cd example-versioning

该命令拉取了一个包含单个脚本 train.pyDVC 项目,该脚本将用于训练模型。

现在我们来安装依赖项。但在开始之前,我们强烈建议创建一个 虚拟环境

$ python3 -m venv .env
$ source .env/bin/activate
$ pip install -r requirements.txt

您克隆的仓库已经初始化了 DVC。其中已包含一个 .dvc/ 目录,内含 config.gitignore 文件。这些以及其他文件和目录对用户是隐藏的,因为通常不需要直接与它们交互。

第一个模型版本

准备工作完成后,我们现在添加一些数据并训练第一个模型。我们将使用 DVC 记录所有内容,包括输入数据集和模型指标

$ dvc get https://github.com/iterative/dataset-registry \
          tutorials/versioning/data.zip
$ unzip -q data.zip
$ rm -f data.zip

dvc get 可以从DVC 仓库(以及远程存储的内容)中下载任意被追踪的文件或目录。它类似于 wget,但适用于 DVC 或 Git 仓库。在此示例中,我们使用自己的数据集注册表仓库作为数据源(更多详情请参阅数据注册表)。

该命令会下载并解压我们的原始数据集,其中包括 1000 张用于训练的带标签图像和 800 张用于验证的带标签图像。总共是一个 43 MB 的数据集,目录结构如下所示:

data
├── train
│   ├── dogs
│   │   ├── dog.1.jpg
│   │   ├── ...
│   │   └── dog.500.jpg
│   └── cats
│       ├── cat.1.jpg
│       ├── ...
│       └── cat.500.jpg
└── validation
   ├── dogs
   │   ├── dog.1001.jpg
   │   ├── ...
   │   └── dog.1400.jpg
   └── cats
       ├── cat.1001.jpg
       ├── ...
       └── cat.1400.jpg

(谁不爱 ASCII 风格的目录图呢?)

让我们使用 dvc add 来记录当前数据集的状态:

$ dvc add data

你可以使用此命令来替代对过大而无法用 Git 跟踪的文件或目录执行 git add:通常是输入数据集、模型、某些中间结果等。该命令会告诉 Git 忽略该目录,并将其放入缓存中(同时在工作区保留一个文件链接,以便你可以像以前一样继续工作)。这是通过创建一个微小且人类可读的.dvc文件实现的,该文件作为指向缓存的指针。

接下来,我们使用 train.py 训练我们的第一个模型。由于数据集较小,此训练过程应该足够轻量,可以在大多数计算机上合理时间内完成(几分钟)。该命令输出一系列文件,其中包括 model.weights.h5metrics.csv,即训练后模型的权重和指标历史记录。捕获当前模型版本最简单的方法是再次使用dvc add

$ python train.py
$ dvc add model.weights.h5

我们在这里手动添加了模型输出,这并不理想。捕获命令输出的推荐方式是使用dvc stage add。稍后会详细介绍这一点。

让我们提交当前状态:

$ git add data.dvc model.weights.h5.dvc metrics.csv .gitignore
$ git commit -m "First model, trained with 1000 images"
$ git tag -a "v1.0" -m "model v1.0, 1000 images"

正如我们之前简要提到的,DVC 不会通过 Git 提交 data/ 目录和 model.weights.h5 文件。相反,dvc add 将它们存储在缓存中(通常位于 .dvc/cache),并将其添加到 .gitignore

在这种情况下,我们创建了 data.dvcmodel.weights.h5.dvc,其中包含指向缓存数据的文件哈希值。然后我们使用 git commit 提交这些.dvc 文件。

请注意,执行 train.py 会产生其他中间文件。这没有问题,我们稍后会使用它们。

$ git status
...
      bottleneck_features_train.npy
      bottleneck_features_validation.npy`

第二个模型版本

假设我们的图像数据集大小翻倍。以下命令将提取 500 张新的猫图片和 500 张新的狗图片到 data/train 中:

$ dvc get https://github.com/iterative/dataset-registry \
          tutorials/versioning/new-labels.zip
$ unzip -q new-labels.zip
$ rm -f new-labels.zip

为了简化,我们保持验证子集不变。现在我们的数据集有 2000 张用于训练的图片和 800 张用于验证的图片,总大小为 67 MB:

data
├── train
│   ├── dogs
│   │   ├── dog.1.jpg
│   │   ├── ...
│   │   └── dog.1000.jpg
│   └── cats
│       ├── cat.1.jpg
│       ├── ...
│       └── cat.1000.jpg
└── validation
   ├── dogs
   │   ├── dog.1001.jpg
   │   ├── ...
   │   └── dog.1400.jpg
   └── cats
       ├── cat.1001.jpg
       ├── ...
       └── cat.1400.jpg

我们现在希望利用这些新标签重新训练模型:

$ dvc add data
$ python train.py
$ dvc add model.weights.h5

让我们提交第二个版本:

$ git add data.dvc model.weights.h5.dvc metrics.csv
$ git commit -m "Second model, trained with 2000 images"
$ git tag -a "v2.0" -m "model v2.0, 2000 images"

就这样!我们已经在 DVC 中跟踪了数据集、模型和指标的第二个版本,并通过 Git 提交了指向它们的.dvc 文件。现在让我们看看如果需要,DVC 如何帮助我们回退到之前的版本。

在工作区版本之间切换

DVC 中用于获取特定已提交数据版本的命令设计得类似于 git checkout。在我们的情况下,只需额外运行dvc checkout,即可将正确的数据恢复到工作区

有两种方式可以实现这一点:完整工作区检出,或特定数据或模型文件的检出。我们先来看完整的检出。它非常直接:

$ git checkout v1.0
$ dvc checkout

这些命令会将工作区恢复到我们最早创建的第一个快照:代码、数据文件、模型,全部内容都会恢复。DVC 对此操作进行了优化,避免每次复制数据或模型文件。因此即使你拥有大型数据集、数据文件或模型,dvc checkout 也很快。

另一方面,如果我们想保留当前代码,但回退到之前的数据集版本,我们可以针对特定数据进行操作,如下所示:

$ git checkout v1.0 data.dvc
$ dvc checkout data.dvc

如果运行 git status,你会看到 data.dvc 已被修改,当前指向数据集的 v1.0 版本,而代码和模型文件则来自 v2.0 标签。

自动化捕获

当你需要跟踪来自源项目的不同版本的数据集或模型文件时,使用 dvc add 是合理的。上面的 data/ 目录(包含猫和狗的图像)就是一个很好的例子。

另一方面,有些文件是运行某些代码后生成的结果。在我们的示例中,train.py 生成了二进制文件(例如 bottleneck_features_train.npy)、模型文件 model.weights.h5 以及指标文件 metrics.csv

当你有一个脚本,接收某些数据作为输入并产生其他数据输出时,更好的方式是使用 dvc stage add 来捕获它们:

如果你尝试过在工作区版本之间切换章节中的命令,请先回到主分支的代码和数据,并删除 model.weights.h5.dvc 文件,命令如下:

$ git checkout master
$ dvc checkout
$ dvc remove model.weights.h5.dvc
$ dvc stage add -n train -d train.py -d data \
          -o model.weights.h5 -o bottleneck_features_train.npy \
          -o bottleneck_features_validation.npy -M metrics.csv \
          python train.py
$ dvc repro

dvc stage add 会在 dvc.yaml 中写入一个名为 train 的管道阶段(通过 -n 选项指定)。它会像 dvc add 一样跟踪所有输出(-o)。但与 dvc add 不同的是,dvc stage add 还会跟踪依赖项(-d)以及用于生成结果的命令(python train.py)。

此时,你可以运行 git add .git commit,将 train 阶段及其输出保存到仓库中。

当任何一个依赖项(-d)发生变化时,dvc repro 就会重新运行 train 阶段。例如,当我们添加新图像以构建模型的第二个版本时,这就属于依赖项变更。该命令还会更新输出并将它们放入缓存中。

为了让事情更清晰一些:dvc adddvc checkout 提供了模型和大型数据集版本管理的基本机制;而 dvc stage adddvc repro 则为机器学习模型提供了一套构建系统,类似于软件构建自动化工具 Make

接下来做什么?

在本示例中,我们的重点是让你亲身体验数据集和机器学习模型的版本控制。我们特别关注了 dvc adddvc checkout 命令。此外,我们也想简要介绍一些你可能感兴趣的后续主题和思路,帮助你进一步了解 DVC 及其如何简化机器学习项目的管理。

首先,你可能已经注意到,训练模型的脚本是以一种整体化的方式编写的。每次运行时,它都会调用 save_bottleneck_feature 函数来预计算网络底层“冻结”的部分,并将特征写入文件。其初衷可能是第一次运行后可以注释掉 save_bottleneck_feature,但每当数据集发生变化时都需要手动记住这一点,这并不方便。

DVC 的 pipelines 功能在此派上用场。我们在介绍 dvc stage adddvc repro 时曾简要提及它。下一步是将脚本拆分为两部分并使用数据管道。请参阅 入门:数据管道 以动手实践管道功能,并尝试在此处应用它。如有疑问,欢迎随时加入我们的 社区 提问!

我们在这里只是简单提到的另一个细节,是通过 dvc stage add 命令的 -M 选项来捕获 metrics.csv 指标文件的方式。将此 输出 标记为指标后,我们便可以跨 Git 标签或分支(例如代表不同实验)比较其数值。更多关于使用 DVC 管理指标的信息,请参阅 dvc metrics比较变更比较多个实验

内容

🐛 发现问题?告诉我们!或者修复它:

在 GitHub 上编辑

有疑问?加入我们的聊天,我们会为您提供帮助:

Discord 聊天