在 GitHub 上编辑

dvc.yaml

您可以在一个或多个 dvc.yaml 文件中配置机器学习项目。stages 列表通常是 dvc.yaml 文件中最重要的部分,但该文件也可用于配置 artifactsmetricsparamsplots,既可以作为阶段定义的一部分,也可以独立存在。

dvc.yaml 使用 YAML 1.2 格式,并采用以下说明的人性化结构。我们建议您熟悉其格式,以便能够自行修改、编写或生成这些文件。

dvc.yaml 文件设计得足够小,您可以轻松地使用 Git 对其进行版本管理,与其他 DVC 文件 和项目代码一起提交。

制品

本节允许您声明有关 artifacts 的结构化元数据。

artifacts:
  cv-classification: # artifact ID (name)
    path: models/resnet.pt
    type: model
    desc: 'CV classification model, ResNet50'
    labels:
      - resnet50
      - classification
    meta:
      framework: pytorch

对于每个 artifact ID,您可以指定以下元素(仅 path 为必填项):

  • path (字符串) - artifact 的路径,可以是相对于仓库根目录的相对路径,也可以是 S3 等外部存储中的完整路径。
  • type (字符串) - 您可以指定任意 type 类型的 artifact。默认情况下,基于 DVC 的 模型注册表 将显示类型为 model 的所有 artifacts(您可以调整过滤器以显示其他类型的 artifacts)。
  • desc (字符串) - 对您的 artifact 的描述
  • labels (列表) - 您希望添加到 artifact 的任何标签
  • meta - 任何额外信息,此元素的内容将被 DVC 忽略,且不会出现在 模型注册表

Artifact ID 必须由字母和数字组成,并使用 '-' 作为分隔符(但不能在开头或结尾使用)。

要从基于旧版 GTO 的模型注册表迁移,将 artifact 注解从 artifacts.yaml 移动到 dvc.yaml,请使用 此辅助脚本

Metrics

metrics 列表包含一个或多个指向 metrics 文件的路径。示例如下:

metrics:
  - metrics.json

Metrics 是保存在结构化文件中的键值对,将指标名称映射到数值。更多信息以及如何在实验之间进行比较,请参见 dvc metrics,或使用 DVCLive 记录指标。

Params

params 列表包含一个或多个指向 参数 文件的路径。示例如下:

params:
  - params.yaml

参数是保存在结构化文件中的键值对。与细粒度的阶段级 参数依赖项 不同,顶层参数在文件级别定义,并包含文件中的所有参数。更多信息以及如何在实验之间进行比较,请参见 dvc params

Plots

plots 列表包含一个或多个用户自定义的 dvc plots 配置。每个图表必须具有唯一的 ID,该 ID 可以是文件或目录路径(相对于 dvc.yaml 的位置),也可以是任意字符串。如果 ID 是任意字符串,则必须在 y 字段中提供文件路径(x 文件路径始终为可选项,且不能单独提供)。

更多示例请参阅 可视化图表dvc plots show,并参考 DVCLive 获取用于记录图表的辅助工具。

可用配置字段

  • y (字符串、列表、字典) - Y 轴数据来源:

    如果图表 ID 是路径,则应提供一个或多个列/字段名称,默认使用最后一个列/字段。例如:

    plots:
      - regression_hist.csv:
          y: mean_squared_error
      - classifier_hist.csv:
          y: [acc, loss]

    如果图表 ID 是任意字符串,则应提供一个将文件路径映射到列/字段名称的字典。例如:

    plots:
      - train_val_test:
          y:
            train.csv: [train_acc, val_acc]
            test.csv: test_acc
  • x (字符串、字典) - X 轴数据来源。默认使用自动生成的 step 字段。

    如果图表 ID 是路径,则应提供一个列/字段名称。例如:

    plots:
      - classifier_hist.csv:
          y: [acc, loss]
          x: epoch

    如果图表 ID 是任意字符串,x 可以是一个列/字段名称,也可以是一个将每个文件路径映射到一个列/字段名称的字典(列/字段名称的数量必须与 y 中的数量匹配)。

    plots:
      - train_val_test: # single x
          y:
            train.csv: [train_acc, val_acc]
            test.csv: test_acc
          x: epoch
      - roc_vs_prc: # x dict
          y:
            precision_recall.json: precision
            roc.json: tpr
          x:
            precision_recall.json: recall
            roc.json: fpr
      - confusion: # different x and y paths
          y:
            dir/preds.csv: predicted
          x:
            dir/actual.csv: actual
          template: confusion
  • y_label (字符串) - Y 轴标签。如果所有 y 数据源具有相同的字段名,则以此为默认值;否则为 "y"。

  • x_label (字符串) - X 轴标签。如果所有 y 数据源具有相同的字段名,则以此为默认值;否则为 "x"。

  • title (字符串) - 图表的标题。默认为 path/to/dvc.yaml::plot_id

  • template (字符串) - 图表模板。默认为 linear

阶段

您可以通过在一个或多个 阶段 中定义独立的 dvc.yaml 文件来构建机器学习流水线。当这些阶段相互连接时(形成一个 依赖图,参见 dvc dag),它们就构成了一个流水线。

stages 列表包含一个或多个用户定义的 阶段。以下是一个名为 transpose 的简单示例:

stages:
  transpose:
    cmd: ./trans.r rows.txt > columns.txt
    deps:
      - rows.txt
    outs:
      - columns.txt

有一个辅助命令组 dvc stage,可用于创建和列出阶段。

阶段中唯一必需的部分是其执行的 shell 命令(cmd 字段)。这是 DVC 在重新运行阶段时所执行的内容(参见 dvc repro)。

我们的示例使用 GNU/Linux,但也可以使用 Windows 或其他 shell。

如果某个 阶段命令 读取输入文件,则可以将这些文件(或其所在目录)定义为 依赖项deps)。DVC 将检查它们是否发生变化,以决定该阶段是否需要重新执行(参见 dvc status)。

如果它写入文件或目录,则可以将这些内容定义为 输出outs)。DVC 将会持续跟踪这些内容(类似于对它们使用 dvc add)。

输出文件可能成为 图表 的有效数据源。

请参阅完整的阶段条目 规范

阶段命令

stages 中定义的命令(cmd 字段)可以是系统终端能够接受并执行的任何内容,例如 shell 内置命令、表达式,或 PATH 中能找到的可执行二进制文件。

如果命令包含特殊字符如 |<>,请使用双引号 " 将其括起来。如果命令中包含需要动态求值的环境变量,则应改用单引号 '

此规则同样适用于辅助命令的 command 参数(如 dvc stage add),否则这些特殊字符将作用于 DVC 本身的调用。

$ dvc stage add -n a_stage "./a_script.sh > /dev/null 2>&1"

另请参阅 模板化(以及字典解包),了解对 cmd 字符串进行参数化的实用方法。

我们并不想规定您如何编写代码或使用何种程序!但请注意,为了防止 DVC 在重现实验阶段时出现意外结果,建议您的底层代码遵循以下原则:

  • 仅从指定的依赖项输出(包括参数文件、指标和图表)中读取或写入数据。
  • 完全重写输出,不要追加或修改已有内容。
  • command 执行结束时,停止对文件的读写操作。

此外,如果您的管道可复现目标还包括输出数据的一致性,那么代码应当是确定性的(即对于相同的输入始终产生相同的输出):避免使用会增加的代码(例如随机数、时间函数、硬件依赖等)。

参数

参数是从结构化的参数文件中由 command 代码读取的简单键值对。它们在 dvc.yamlparams 字段中按阶段定义,应包含以下内容之一:

  1. 可在 params.yaml(默认参数文件)中找到的参数名称;
  2. 以自定义参数文件路径命名的字典,并包含一个需在该文件中查找的参数键值对列表;
  3. 以参数文件路径命名的空集合(不提供值或使用 null):用于动态追踪该文件中的所有参数。

以点分隔的参数名会被解析为树形路径,用于在参数文件中定位对应值。

stages:
  preprocess:
    cmd: bin/cleanup raw.txt clean.txt
    deps:
      - raw.txt
    params:
      - threshold # track specific param (from params.yaml)
      - nn.batch_size
      - myparams.yaml: # track specific params from custom file
          - epochs
      - config.json: # track all parameters in this file
    outs:
      - clean.txt

参数是一种更细粒度的阶段依赖类型:多个 stages 可共享同一个参数文件,但只有其中特定的值会影响各自的状态(参见 dvc status)。

参数文件

支持的参数文件格式包括 YAML 1.2、JSON、TOML 1.0,以及 Python。参数的键值对应组织成树状层次结构。支持的值类型有:字符串、整数、浮点数、布尔值和数组(参数组)。

这些文件通常手动编写(或自动生成),可直接通过 Git 与其他工作区文件一起进行版本管理。

另请参阅 dvc params diff,用于比较项目不同版本间的参数差异。

foreach 阶段

查看 matrix 阶段,了解一种更强大的方式来定义多个阶段。

您可以通过以下语法,在单个 dvc.yaml 条目中定义多个阶段。foreach 元素接受一个包含待迭代值的列表或字典,而 do 则包含常规的阶段字段(如 cmdouts 等)。以下是一个简单示例:

stages:
  cleanups:
    foreach: # List of simple values
      - raw1
      - labels1
      - raw2
    do:
      cmd: clean.py "${item}"
      outs:
        - ${item}.cln

执行 dvc repro 时,列表中的每个项目会通过将值代入表达式 ${item} 而扩展为独立的阶段。项目的值会被附加到每个阶段名称后,并以 @ 分隔。foreach 语法生成的最终阶段将保存至 dvc.lock 文件中:

schema: '2.0'
stages:
  cleanups@labels1:
    cmd: clean.py "labels1"
    outs:
      - path: labels1.cln
  cleanups@raw1:
    cmd: clean.py "raw1"
    outs:
      - path: raw1.cln
  cleanups@raw2:
    cmd: clean.py "raw2"
    outs:
      - path: raw2.cln

对于包含复杂值(例如字典)的列表,替换表达式可使用 ${item.key} 的形式。阶段名称将以从零开始的索引编号结尾。例如:

stages:
  train:
    foreach:
      - epochs: 3
        thresh: 10
      - epochs: 10
        thresh: 15
    do:
      cmd: python train.py ${item.epochs} ${item.thresh}
# dvc.lock
schema: '2.0'
stages:
  train@0:
    cmd: python train.py 3 10
  train@1:
    cmd: python train.py 10 15

DVC 还可以在直接提供给 foreach 的字典上进行迭代,从而提供两个可用的替换表达式:${key}${item}。前者用于生成阶段名称:

stages:
  build:
    foreach:
      uk:
        epochs: 3
        thresh: 10
      us:
        epochs: 10
        thresh: 15
    do:
      cmd: python train.py '${key}' ${item.epochs} ${item.thresh}
      outs:
        - model-${key}.hdfs
# dvc.lock
schema: '2.0'
stages:
  build@uk:
    cmd: python train.py 'uk' 3 10
    outs:
      - path: model-uk.hdfs
        md5: 17b3d1efc339b416c4b5615b1ce1b97e
  build@us: ...

所生成的各个阶段(如 train@1build@uk)以及源组(如 trainbuild)均可在支持阶段目标的命令中使用,例如 dvc reprodvc stage list

重要的是,来自 参数文件 的字典也可在 foreach 阶段中使用:

stages:
  mystages:
    foreach: ${myobject} # From params.yaml
    do:
      cmd: ./script.py ${key} ${item.prop1}
      outs:
        - ${item.prop2}

无论是单个的 foreach 阶段(如 train@1),还是 foreach 阶段组(如 train),都可以在支持阶段目标的命令中使用。

matrix 阶段

matrix 可用于基于变量组合定义多个阶段。matrix 元素接受一个或多个变量,每个变量在其值列表上进行迭代。例如:

stages:
  train:
    matrix:
      model: [cnn, xgb]
      feature: [feature1, feature2, feature3]
    cmd: ./train.py --feature ${item.feature} ${item.model}
    outs:
      - ${key}.pkl # equivalent to: ${item.model}-${item.feature}.pkl

您可以在阶段定义中使用 item 字典键来引用每个变量。在上述示例中,您可以访问 item.modelitem.feature。此外,matrix 提供了一个 key 值,它将当前的 item 值组合成一个表达式(见下文示例)。

当运行 dvc repro 时,DVC 会根据变量的所有可能组合展开为多个阶段。以上示例中,DVC 将创建六个阶段,每个对应一个 modelfeature 的组合。阶段名称将通过在原始阶段名后添加变量值并以 @ 分隔的方式生成,与 foreach 相同。例如,DVC 将创建如下阶段:

$ dvc stage list
train@cnn-feature1  Outputs cnn-feature1.pkl
train@cnn-feature2  Outputs cnn-feature2.pkl
train@cnn-feature3  Outputs cnn-feature3.pkl
train@xgb-feature1  Outputs xgb-feature1.pkl
train@xgb-feature2  Outputs xgb-feature2.pkl
train@xgb-feature3  Outputs xgb-feature3.pkl

无论是单个 matrix 阶段(例如:train@cnn-feature1),还是 matrix 阶段组(train),均可在支持阶段目标的命令中使用。

变量中的值可以是字符串、整数等简单值,也可以是列表、字典等复合值。例如:

matrix:
  config:
    - n_estimators: 150
      max_depth: 20
    - n_estimators: 120
      max_depth: 30
  labels:
    - [label1, label2, label3]
    - [labelX, labelY, labelZ]

当使用列表或字典时,DVC 将根据变量名和值的索引生成阶段名称。以上示例中,生成的阶段名称可能类似于 train@labels0-config0

模板化 也可在 matrix 中使用,因此您可以引用在其他地方定义的 变量。例如,您可以在 params.yaml 文件中定义值,并在 matrix 中使用它们。

# params.yaml
datasets: [dataset1/, dataset2/]
processors: [processor1, processor2]
# dvc.yaml
stages:
  preprocess:
    matrix:      processor: ${processors}      dataset: ${datasets}
    cmd: ./preprocess.py ${item.dataset} ${item.processor}
    deps:
    - ${item.dataset}
    outs:
    - ${item.dataset}-${item.processor}.json

阶段条目

以下是每个阶段可接受的字段:

字段描述
cmd(必需)一个或多个要执行的 shell 命令(可以包含单个值或列表)。cmd 的值可使用来自参数文件的字典替换。命令将按顺序执行,直到全部完成或其中一个失败(参见 dvc repro)。
wdircmd 运行的工作目录(相对于文件所在位置)。其他字段中的任何路径也基于此目录。默认为 .(即文件所在位置)。
deps依赖项路径列表(相对于 wdir)。
outs输出路径列表(相对于 wdir)。这些路径可包含某些可选的子字段
params要从 params.yaml(位于 wdir 中)跟踪的参数依赖键(字段名)列表。该列表还可以包含其他参数文件的名称,并附带一个子列表,说明需在这些文件中跟踪的参数名称。
frozen此阶段是否被冻结(在重新运行时禁止执行)
always_changed使该阶段始终被dvc statusdvc repro等命令视为已更改。默认为 false
meta(可选)可通过此字段手动添加任意元数据。支持任何 YAML 内容。meta 的内容会被 DVC 忽略,但对于直接读取或写入.dvc 文件的用户进程可能具有意义。
desc(可选)用户描述。这不会影响任何 DVC 操作。

dvc.yaml 文件也支持 # 注释

我们维护了一个 dvc.yaml 模式定义,可供 VSCodePyCharm 等编辑器使用,以实现自动语法验证和自动补全。

另请参阅 如何解决合并冲突

输出子字段

这些字段包含 .dvc 文件输出条目中部分字段的子集。

字段描述
cache此文件或目录是否被缓存(默认为 true)。参见 dvc add--no-commit 选项。如果某个阶段的任一输出设置了 cache: false,则该阶段的[运行缓存]将被禁用。
remote(可选)用于推送/拉取的远程存储名称
persist在执行 dvc repro 期间,输出文件/目录是否应保留在原位(默认为 false:当 dvc repro 开始时,输出将被删除)
desc(可选)此输出的用户描述。这不会影响任何 DVC 操作。
push此前已缓存的此文件或目录是否由 dvc push 上传到远程存储(默认为 true)。

模板功能

dvc.yaml 支持一种模板格式,可将来自不同源的值插入 YAML 结构本身。这些源可以是参数文件,也可以是在 dvc.yaml 中定义的 vars

假设我们有一个 params.yaml 文件(默认参数文件),其内容如下:

models:
  us:
    threshold: 10
    filename: 'model-us.hdf5'
codedir: src

这些值可以在 dvc.yaml 的任意位置通过 ${} 替换表达式 使用,例如作为命令行参数传递给阶段命令

artifacts:
  model-us:
    path: ${models.us.filename}
    type: model

stages:
  build-us:
    cmd: >-
      python ${codedir}/train.py
      --thresh ${models.us.threshold}
      --out ${models.us.filename}
    outs:
      - ${models.us.filename}:
          cache: true

DVC 将跟踪在 ${} 中使用的简单参数值(如数字、字符串等)(这些值将被 dvc params diff 列出)。

仅在 cmd 条目中,你还可以在 ${} 中引用一个字典,DVC 将会对其进行解包。这有助于避免写出传递给命令的每一个参数,或在参数变更时修改 dvc.yaml

从 Python 代码中加载参数的另一种方式是使用 dvc.api.params_show() API 函数。

例如,假设有以下 params.yaml 文件:

mydict:
  foo: foo
  bar: 1
  bool: true
  nested:
    baz: bar
  list: [2, 3, 'qux']

你可以在阶段命令中像这样引用 mydict

stages:
  train:
    cmd: R train.r ${mydict}

DVC 将解包 mydict 中的值,生成如下 cmd 调用:

$ R train.r --foo 'foo' --bar 1 --bool \
                  --nested.baz 'bar' --list 2 3 'qux'

你可以将此功能与参数解析库(如 R argparseJulia ArgParse)结合使用,让这些库为你完成所有工作。

dvc config parsing 可用于自定义对布尔值和列表等歧义类型所使用的语法。

变量

另一种(不依赖参数文件的)方式是将用于替换的值列为顶级 vars,如下所示:

vars:
  - models:
      us:
        threshold: 10
        filename: 'model-us.hdf5'
  - codedir: src

artifacts:
  model-us:
    path: ${models.us.filename}
    type: model

stages:
  build-us:
    cmd: >-
      python ${codedir}/train.py --thresh ${models.us.threshold} --out
      ${models.us.filename}
    outs:
      - ${models.us.filename}:
          cache: true

来自 vars 的值不会像参数那样被追踪。

要加载额外的参数文件,请按所需顺序将其列在顶级 vars 中,例如:

vars:
  - params.json
  - myvar: 'value'
  - config/myapp.yaml

如果你的仓库中有多个管道,或者你的 params.yaml 文件与 dvc.yaml 文件不在同一目录下,则必须在 vars 中指定参数文件路径,才能使用这些值进行模板化。

注意事项

参数文件路径将相对于 dvc.yaml 文件所在目录进行解析。默认的 params.yaml 如果存在,将始终首先被加载。

也可以使用冒号 : 指定从额外参数文件中包含的内容:

vars:
  - params.json:clean,feats

stages:
  featurize:
    cmd: ${feats.exec}
    deps:
      - ${clean.filename}
    outs:
      - ${feats.dirname}

DVC 会合并来自参数文件或在 vars 中指定的值。例如,{"grp": {"a": 1}} 可以与 {"grp": {"b": 2}} 合并,但不能与 {"grp": {"a": 7}} 合并。

替换表达式支持以下形式:

${param} # Simple
${param.key} # Nested values through . (period)
${param.list[0]} # List elements via index in [] (square brackets)

若要在 dvc.yaml 中字面使用该表达式(即 DVC 不将其替换为值),请使用反斜杠进行转义,例如 \${...

dvc.lock 文件

为了记录你的管道状态并帮助追踪其输出,DVC 会为每个 dvc.yaml 维护一个 dvc.lock 文件。其用途包括:

  • 使 DVC 能够检测到阶段定义或其依赖项是否发生变化。此类情况会使阶段失效,需要重新执行(参见 dvc status)。
  • 追踪管道的中间和最终输出——类似于 .dvc 文件的功能。
  • 多个 DVC 命令的正常运行需要该文件,例如 dvc checkoutdvc get

请勿手动编辑这些文件。DVC 会自动创建和更新它们。

以下是一个示例:

schema: '2.0'
stages:
  features:
    cmd: jupyter nbconvert --execute featurize.ipynb
    deps:
      - path: data/clean
        md5: d8b874c5fa18c32b2d67f73606a1be60
    params:
      params.yaml:
        levels.no: 5
    outs:
      - path: features
        md5: 2119f7661d49546288b73b5730d76485
        size: 154683
      - path: performance.json
        md5: ea46c1139d771bfeba7942d1fbb5981e
        size: 975
      - path: logs.csv
        md5: f99aac37e383b422adc76f5f1fb45004
        size: 695947

阶段会在 dvc.lock 中再次列出,以便知道它们在 dvc.yaml 中的定义是否发生了变化。

常规的依赖项条目以及所有形式的输出条目(包括指标图表文件)也会按阶段列在dvc.lock中,包含一个内容哈希字段(md5etagchecksum)。

完整的参数依赖项(包括键和值)也会列出(位于 params 下),每个参数文件名下列出对应的内容。对于模板化的 dvc.yaml 文件,实际值会被写入dvc.lock(不保留 ${} 表达式)。至于foreach 阶段matrix 阶段,各个阶段会被展开(不保留 foreachmatrix 结构)。

内容

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

在 GitHub 上编辑

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

Discord 聊天