dvc.yaml
您可以在一个或多个 dvc.yaml 文件中配置机器学习项目。stages 列表通常是 dvc.yaml 文件中最重要的部分,但该文件也可用于配置 artifacts、metrics、params 和 plots,既可以作为阶段定义的一部分,也可以独立存在。
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 必须由字母和数字组成,并使用 '-' 作为分隔符(但不能在开头或结尾使用)。
Metrics
metrics 列表包含一个或多个指向 metrics 文件的路径。示例如下:
metrics:
- metrics.jsonMetrics 是保存在结构化文件中的键值对,将指标名称映射到数值。更多信息以及如何在实验之间进行比较,请参见 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 字符串进行参数化的实用方法。
参数
参数是从结构化的参数文件中由 command 代码读取的简单键值对。它们在 dvc.yaml 的 params 字段中按阶段定义,应包含以下内容之一:
- 可在
params.yaml(默认参数文件)中找到的参数名称; - 以自定义参数文件路径命名的字典,并包含一个需在该文件中查找的参数键值对列表;
- 以参数文件路径命名的空集合(不提供值或使用
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 则包含常规的阶段字段(如 cmd、outs 等)。以下是一个简单示例:
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 15DVC 还可以在直接提供给 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@1、build@uk)以及源组(如 train、build)均可在支持阶段目标的命令中使用,例如 dvc repro 和 dvc 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.model 和 item.feature。此外,matrix 提供了一个 key 值,它将当前的 item 值组合成一个表达式(见下文示例)。
当运行 dvc repro 时,DVC 会根据变量的所有可能组合展开为多个阶段。以上示例中,DVC 将创建六个阶段,每个对应一个 model 和 feature 的组合。阶段名称将通过在原始阶段名后添加变量值并以 @ 分隔的方式生成,与 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)。 |
wdir | cmd 运行的工作目录(相对于文件所在位置)。其他字段中的任何路径也基于此目录。默认为 .(即文件所在位置)。 |
deps | 依赖项路径列表(相对于 wdir)。 |
outs | 输出路径列表(相对于 wdir)。这些路径可包含某些可选的子字段。 |
params | 要从 params.yaml(位于 wdir 中)跟踪的参数依赖键(字段名)列表。该列表还可以包含其他参数文件的名称,并附带一个子列表,说明需在这些文件中跟踪的参数名称。 |
frozen | 此阶段是否被冻结(在重新运行时禁止执行) |
always_changed | 使该阶段始终被dvc status 和 dvc repro等命令视为已更改。默认为 false |
meta | (可选)可通过此字段手动添加任意元数据。支持任何 YAML 内容。meta 的内容会被 DVC 忽略,但对于直接读取或写入.dvc 文件的用户进程可能具有意义。 |
desc | (可选)用户描述。这不会影响任何 DVC 操作。 |
dvc.yaml 文件也支持 # 注释。
另请参阅 如何解决合并冲突。
输出子字段
| 字段 | 描述 |
|---|---|
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: trueDVC 将跟踪在 ${} 中使用的简单参数值(如数字、字符串等)(这些值将被 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 argparse 或 Julia 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 checkout或dvc 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中,包含一个内容哈希字段(md5、etag 或 checksum)。
完整的参数依赖项(包括键和值)也会列出(位于 params 下),每个参数文件名下列出对应的内容。对于模板化的 dvc.yaml 文件,实际值会被写入dvc.lock(不保留 ${} 表达式)。至于foreach 阶段和matrix 阶段,各个阶段会被展开(不保留 foreach 或 matrix 结构)。