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.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
字符串进行参数化的实用方法。
参数
参数是从结构化的参数文件中由 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 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@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: 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 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
结构)。