在 GitHub 上编辑

入门:数据管道

点击播放即表示您同意 YouTube 的 隐私政策服务条款

对数据科学中的大型数据文件和目录进行版本控制功能强大,但往往还不够。在训练机器学习模型之前,数据需要经过过滤、清洗和转换——为此,DVC 引入了一个构建系统,用于定义、执行和跟踪数据管道(data pipelines),即一系列数据处理阶段,最终生成一个结果。

💫 DVC 是机器学习项目的“Makefile”系统!

DVC 管道通过 Git 进行版本控制,使你能够更好地组织项目,并随时复现完整的工作流和结果。你可以记录一个简单的 ETL 工作流,组织你的项目结构,或构建一个复杂的 DAG(有向无环图)管道。

稍后,我们将发现 DVC 允许你在这些管道的基础上管理机器学习实验——控制其执行过程、注入参数等。

设置

在已初始化的 DVC 项目中,我们先获取一些示例代码以进行后续步骤:

$ wget https://code.dvc.org/get-started/code.zip
$ unzip code.zip && rm -f code.zip

通过以下方式获取示例代码:

$ tree
.
├── params.yaml
└── src
    ├── evaluate.py
    ├── featurization.py
    ├── prepare.py
    ├── requirements.txt
    └── train.py

运行此示例所需的数据可通过 dvc get 下载,并使用 dvc add 跟踪(如果你是从数据版本控制章节一路跟过来的,可能已经拥有这些数据):

$ dvc get https://github.com/iterative/dataset-registry \
          get-started/data.xml -o data/data.xml
$ dvc add data/data.xml

现在,让我们完成一些常见的项目设置步骤(虚拟环境、依赖项、Git)。

首先,创建并使用一个虚拟环境(这不是必须的,但我们强烈推荐这样做):

$ virtualenv venv && echo "venv" > .gitignore
$ source venv/bin/activate

接下来,安装 Python 依赖项:

$ pip install -r src/requirements.txt

最后,现在是将代码提交到 Git 的好时机:

$ git add .github/ data/ params.yaml src .gitignore
$ git commit -m "Initial commit"

管道阶段

使用 dvc stage add 创建阶段(stages)。这些阶段代表处理步骤(通常是用 Git 跟踪的脚本/代码),并组合形成完整的管道。阶段可以将代码与其对应的数据输入输出连接起来。让我们将一个 Python 脚本转换为一个阶段

$ dvc stage add -n prepare \
                -p prepare.seed,prepare.split \
                -d src/prepare.py -d data/data.xml \
                -o data/prepared \
                python src/prepare.py data/data.xml

会生成一个 dvc.yaml 文件。其中包含我们要运行的命令(python src/prepare.py data/data.xml)、它的依赖项输出项的信息。

DVC 使用管道定义来自动跟踪每个阶段所使用的和生成的数据,因此无需手动对 data/prepared 执行 dvc add

上述命令选项的详细说明:

  • -n prepare 指定阶段的名称。如果你打开 dvc.yaml 文件,会看到一个名为 prepare 的部分。

  • -p prepare.seed,prepare.split 定义了一种特殊类型的依赖项——参数。任何阶段都可以依赖参数文件中的参数值(默认为 params.yaml)。我们将在指标、参数和图表页面中进一步讨论这些内容。

prepare:
  split: 0.20
  seed: 20170428
  • -d src/prepare.py-d data/data.xml 表示该阶段依赖于这些文件(依赖项)才能运行。请注意,源代码本身也被标记为依赖项。如果其中任何一个文件发生变化,当执行管道时,DVC 就会知道该阶段需要被重新运行

  • -o data/prepared 指定该脚本的输出目录,脚本会在其中写入两个文件。

    这是运行后工作区的结构:

     .
     ├── data
     │   ├── data.xml
     │   ├── data.xml.dvc
    +│   └── prepared
    +│       ├── test.tsv
    +│       └── train.tsv
    +├── dvc.yaml
    +├── dvc.lock
     ├── params.yaml
     └── src
         ├── ...
  • 最后一行,python src/prepare.py data/data.xml 是此阶段要运行的命令,它会被保存到 dvc.yaml 文件中,如下所示。

生成的 prepare 阶段包含了上述所有信息:

stages:
  prepare:
    cmd: python src/prepare.py data/data.xml
    deps:
      - src/prepare.py
      - data/data.xml
    params:
      - prepare.seed
      - prepare.split
    outs:
      - data/prepared

DVC 可以通过将所有数据保留在项目内来简化工作流,但如果已有大型数据集存储在其他位置且不想复制,或某个阶段直接将数据写入云存储时,这种方式并不总是实用。DVC 仍能检测到这些外部数据集的变化。你的管道依赖项可以指向任意位置,而不仅限于项目内的本地路径。输出也是如此,但你需要设置 cache: false 来告诉 DVC 不要对这些外部输出创建本地副本。请参见下文示例,或阅读 外部依赖项和输出 了解更多信息。

stages:
  prepare:
    cmd:
      - wget
        https://sagemaker-sample-data-us-west-2.s3-us-west-2.amazonaws.com/autopilot/direct_marketing/bank-additional.zip
        -O bank-additional.zip
      - python sm_prepare.py --bucket mybucket --prefix project-data
    deps:
      - sm_prepare.py
      - https://sagemaker-sample-data-us-west-2.s3-us-west-2.amazonaws.com/autopilot/direct_marketing/bank-additional.zip
    outs:
      - s3://mybucket/project-data/input_data:
          cache: false

添加阶段后,你可以使用 dvc repro 运行整个管道。

依赖图

通过多次使用 dvc stage add,并将某个阶段的输出定义为另一个阶段的依赖项,我们可以描述一系列相互依赖的命令,最终得到期望的结果。这就是我们所说的依赖图,它构成了一个完整且连贯的管道。

让我们创建第二个与 prepare 阶段输出相连的阶段,用于执行特征提取:

$ dvc stage add -n featurize \
                -p featurize.max_features,featurize.ngrams \
                -d src/featurization.py -d data/prepared \
                -o data/features \
                python src/featurization.py data/prepared data/features

现在 dvc.yaml 文件将被更新以包含这两个阶段。

最后,让我们添加第三个 train 阶段:

$ dvc stage add -n train \
                -p train.seed,train.n_est,train.min_split \
                -d src/train.py -d data/features \
                -o model.pkl \
                python src/train.py data/features model.pkl

最终,我们的 dvc.yaml 应该包含全部三个阶段。

此时最好使用 Git 提交这些更改。这些更改包括 .gitignore 文件和 dvc.yaml —— 后者描述了我们的管道。

$ git add .gitignore data/.gitignore dvc.yaml
$ git commit -m "pipeline defined"

很好!现在我们可以运行这个管道了。

重新运行(Reproducing)

dvc.yaml 中的管道定义使我们能够轻松地重现整个流程:

$ dvc repro

你会注意到系统创建了一个 dvc.lock 文件(即“状态文件”),用于记录此次运行的结果。

dvc repro 依赖于 依赖图(在 dvc.yaml 中定义),并利用 dvc.lock 来确定具体需要运行哪些部分。

dvc.lock 文件类似于 .dvc 文件 —— 它记录了所用依赖项的哈希值(大多数情况下是 md5)以及参数的取值。它可以被视为管道的状态

schema: '2.0'
stages:
  prepare:
    cmd: python src/prepare.py data/data.xml
    deps:
      - path: data/data.xml
        md5: 22a1a2931c8370d3aeedd7183606fd7f
        size: 14445097
      - path: src/prepare.py
        md5: f09ea0c15980b43010257ccb9f0055e2
        size: 1576
    params:
      params.yaml:
        prepare.seed: 20170428
        prepare.split: 0.2
    outs:
      - path: data/prepared
        md5: 153aad06d376b6595932470e459ef42a.dir
        size: 8437363
        nfiles: 2

可以使用 dvc status 命令来比较工作区与当前实际状态之间的差异。

最佳实践是在 dvc.lock 创建或修改后立即提交到 Git,以记录当前的状态和结果:

$ git add dvc.lock && git commit -m "first pipeline repro"

让我们尝试稍微玩点花样。首先,更改训练阶段的一个参数:

  1. 打开 params.yaml 文件,将 n_est 改为 100,然后
  2. (重新)运行 dvc repro

你会看到:

$ dvc repro
Stage 'prepare' didn't change, skipping
Stage 'featurize' didn't change, skipping
Running stage 'train' with command: ...

DVC 检测到只需运行 train 阶段,其余部分都被跳过!所有中间结果都被复用了。

现在,让我们将其改回 50 并再次运行 dvc repro

$ dvc repro
Stage 'prepare' didn't change, skipping
Stage 'featurize' didn't change, skipping

和之前一样,无需重新运行 preparefeaturize 等步骤。但这一次,它也不会重新运行 train!此前使用相同输入集(参数和数据)的运行结果已被保存在 DVC 的 运行缓存 中,并被直接复用。

可视化

构建完我们的流水线后,我们需要一种有效的方式来理解其结构。将其可视化为连接各阶段的图有助于实现这一点。DVC 允许你在不离开终端的情况下完成该操作!

$ dvc dag
         +---------+
         | prepare |
         +---------+
              *
              *
              *
        +-----------+
        | featurize |
        +-----------+
              *
              *
              *
          +-------+
          | train |
          +-------+

请参考 dvc dag 了解此命令可视化的其他方式。

总结

DVC 流水线(dvc.yaml 文件、dvc stage adddvc repro 命令)解决了几个重要问题:

  • 自动化:以“智能”方式运行一系列步骤,从而加快项目迭代速度。DVC 能自动确定项目中需要重新运行的部分,并对“运行”及其结果进行缓存,避免不必要的重复执行。
  • 可复现性dvc.yamldvc.lock 文件描述了应使用的数据以及生成流水线结果(例如机器学习模型)所需的命令。将这些文件存储在 Git 中,便于版本控制和共享。
  • 面向机器学习的持续交付与持续集成(CI/CD):以可构建和可复现的方式描述项目,是引入 CI/CD 系统的前提条件。可查看我们的姊妹项目 CML 获取一些示例。
内容

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

在 GitHub 上编辑

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

Discord 聊天