repro
根据需要按正确顺序运行 流水线 的 阶段,以复现完整或部分流水线。
概要
usage: dvc repro [-h] [-q | -v] [-f] [-i]
[-s] [-p] [-P] [-R]
[--downstream] [--force-downstream]
[--pull] [--allow-missing] [--dry]
[--glob] [--no-commit] [--no-run-cache]
[-k] [--ignore-errors]
[targets [<target> ...]]
positional arguments:
targets Stages to reproduce. 'dvc.yaml' by default.
详见
targets
。
描述
通过恢复在 dvc.yaml
中列出的阶段之间定义的 依赖关系图,提供一种重新生成数据流水线结果的方法。然后检查各个阶段,确定哪些需要运行(参见 dvc status
)。最后执行 它们的命令。
这类似于软件构建自动化中的 make
,但 DVC 会捕获“构建需求”(阶段的依赖项),并在过程中缓存流水线的输出。
注意事项
通常在定义一个或多个阶段后(参见 dvc.yaml
和 dvc stage add
),或者当代码或其他依赖项发生更改或缺失时执行此操作。请注意,除非使用 --pull
选项,否则 dvc repro
不会尝试 dvc checkout
或 dvc pull
数据。
为了方便起见,DVC 提供了一个 Git 钩子,在执行 git commit
后提醒你是否需要运行 dvc repro
。详见 dvc install
。
请记住,一个 dvc.yaml
文件不一定对应一条流水线(尽管通常是这样)。因此 DVC 会读取 工作区 内所有的 dvc.yaml
文件来重建流水线。
不过,有几种方法可以限制需要重新生成的内容:通过指定复现的 targets
,或使用某些命令 选项,例如 --single-item
或 --all-pipelines
。
所有数据文件、中间结果或最终结果都会被缓存(除非使用了 --no-commit
选项),并且根据需要在 dvc.lock
和 .dvc
文件中更新已更改的依赖项和输出的哈希值。
并行执行阶段
如果你需要并行执行阶段,可以同时多次启动 dvc repro
(例如,在多个独立终端中运行)。例如,假设你的 流水线 图结构如下所示:
$ dvc dag
+--------+ +--------+
| A1 | | B1 |
+--------+ +--------+
* *
* *
* *
+--------+ +--------+
| A2 | | B2 |
+--------+ +--------+
* *
** **
* *
+------------+
| train |
+------------+
该流水线包含两个并行分支(A
和 B
),以及在最后合并这两个分支的 train
阶段。如果此时运行 dvc repro
,DVC 会按顺序依次重现实现两个分支,然后执行 train
。若要同时重现实现两个分支,可以同时运行 dvc repro A2
和 dvc repro B2
。当两个分支都成功完成后,再运行 dvc repro train
:DVC 会识别到两个分支均已是最新的状态,仅执行最终阶段。
选项
-
targets
(可选命令参数)— 指定需要重现实验的内容(默认为./dvc.yaml
中的所有流水线)。根据所用标志的不同,可以提供不同类型的目标(详见各选项说明)。例如:dvc repro linear/dvc.yaml
:一个dvc.yaml
文件dvc repro -R pipelines/
:递归查找该目录下的所有流水线文件dvc repro train-model
:./dvc.yaml
中的特定阶段dvc repro modeling/dvc.yaml:prepare
:来自特定dvc.yaml
文件的阶段dvc repro train-model@1
:./dvc.yaml
中的 Foreach 阶段dvc repro --glob train-*
:用于匹配一组阶段名称的模式
-
-R
,--recursive
— 在作为targets
提供的目录及其子目录中递归查找dvc.yaml
文件并进行重现实验。如果目标中不包含任何目录,则此选项无效。 -
--glob
— 将targets
解释为通配符 模式,以匹配阶段名称。例如:train-*
(特定阶段名)或models/dvc.yaml:train-*
(特定dvc.yaml
文件中的阶段)。注意:该选项仅匹配阶段名称,不匹配路径。 -
-s
,--single-item
— 关闭对依赖项变更的递归检查,仅重现实验单个阶段。如果提供了多个阶段名称作为targets
,则这些阶段将被非递归地依次执行。 -
-f
,--force
— 即使未检测到任何更改,也强制重现实验流水线并重新生成结果。默认情况下会执行所有阶段,但可通过targets
参数或-s
、-p
选项限制范围。 -
--no-commit
— 不将本次执行的输出保存到缓存中(仍会创建或更新dvc.yaml
和dvc.lock
);在探索不同数据或阶段时,可用于避免缓存不必要的中间数据。使用dvc commit
可完成后续提交操作。 -
--dry
— 仅打印将要执行的命令,而不实际运行这些命令。 -
-i
,--interactive
— 在重现实验每个阶段前提示用户确认。只有当用户输入 "y" 时,该阶段才会被执行。 -
-p
,--pipeline
- 重新执行包含指定targets
的完整管道。使用dvc dag <target>
查看某个目标的父级管道。 -
-P
,--all-pipelines
- 重新执行 DVC 项目中所有dvc.yaml
文件定义的全部管道。此选项下指定targets
无效,因为所有可能的目标都会被包含。 -
--no-run-cache
- 即使阶段命令及其依赖项和输出此前已运行过,仍强制执行该命令(参见运行缓存)。例如当阶段命令具有非确定性行为时有用(不推荐)。 -
--force-downstream
- 在类似... -> A (已更改) -> B -> C
的情况下,会先重新执行A
,然后继续执行B
,即使B
此前已使用来自A
的相同输入执行过(已被缓存)。准确地说,它会重新执行所有变更阶段的下游阶段,即使这些阶段的直接依赖项未发生变化。当所有阶段共享一个公共依赖时,这种方式非常有用,可仅在第一个相关阶段(如本例中的
A
)声明该依赖,避免重复定义。例如,若已知所有阶段(A
及其后续阶段)都依赖于requirements.txt
,则只需在A
中声明,在B
和C
中可省略。这是一种强制执行未变更阶段的方法。对于包含生成非确定性(半随机)输出的阶段的管道也很有用,因为每次执行输出都可能不同,因此无法信任此类阶段的缓存。
-
--downstream
- 仅在其对应管道中执行给定targets
之后的阶段,包括目标阶段本身。如果未提供targets
,此选项无效。 -
--pull
- 尝试按需下载缺失的数据。包括:(1) 即将运行的阶段的依赖项;(2) 其他未变更但需跳过的阶段的输出;(3) 即将从缓存检出的阶段的运行缓存(除非传入了--no-run-cache
)。 -
--allow-missing
- 跳过仅有数据缺失而无其他变更的阶段。在 DVC>=3.0 版本中,
--allow-missing
不会跳过由 DVC<3.0 保存的数据,因为在 DVC 3.0 中哈希类型发生了变化,DVC 将其视为数据变更。要将数据迁移到新的哈希类型,请运行dvc cache migrate --dvc-files
。更多关于 从 DVC 2.x 升级到 3.0 的信息请参阅相关文档。 -
-k
,--keep-going
- 继续执行,跳过依赖于失败阶段的那些阶段。目标的其他依赖项仍将被执行。 -
--ignore-errors
- 执行阶段时忽略所有错误。与--keep-going
不同,即使阶段依赖于失败的阶段,也会继续执行。 -
-h
,--help
- 打印使用说明/帮助信息,然后退出。 -
-q
,--quiet
- 不向标准输出写入任何内容。如果所有阶段均已最新或全部成功执行,则以退出码 0 结束;否则以退出码 1 结束。阶段中定义的命令仍可自由输出信息,不受此标志影响。 -
-v
,--verbose
- 显示详细的跟踪信息。
示例
要动手实践数据科学和机器学习管道,请参阅 入门:数据管道。
让我们构建并重新执行一个简单的管道。它从这个 text.txt
文件开始:
dvc
1231
is
3
the
best
并进行几次简单的转换来过滤和统计数字:
$ dvc stage add -n filter -d text.txt -o numbers.txt \
"cat text.txt | egrep '[0-9]+' > numbers.txt"
$ dvc stage add -n count -d numbers.txt -d process.py -M count.txt \
"python process.py numbers.txt > count.txt"
其中 process.py
是一个脚本,为简化起见,仅打印行数:
import sys
num_lines = 0
with open(sys.argv[1], 'r') as f:
for line in f:
num_lines += 1
print(num_lines)
执行 dvc repro
的结果应如下所示(cat
用于显示文件内容,tree
用于显示工作目录的内容):
$ dvc repro
Running stage 'filter':
> cat text.txt | egrep '[0-9]+' > numbers.txt
Generating lock file 'dvc.lock'
Updating lock file 'dvc.lock'
Running stage 'count':
> python process.py numbers.txt > count.txt
Updating lock file 'dvc.lock'
Use `dvc push` to send your updates to remote storage.
$ cat count.txt
2
$ tree
.
├── count.txt <---- result: "2"
├── dvc.lock <---- file to record pipeline state
├── dvc.yaml <---- file containing list of stages.
├── numbers.txt <---- intermediate result of the first stage
├── process.py <---- code that implements data transformation
└── text.txt <---- text file to process
你可以检查一下 dvc.lock
和 count.txt
的内容,以便后续参考。
现在,假设我们想要打印一段描述信息,并将以下这行代码添加到 process.py
中:
...
print('Number of lines:')
print(num_lines)
此时如果我们运行 dvc repro
,应该会看到如下输出:
$ dvc repro
Stage 'filter' didn't change, skipping
Running stage 'count' with command:
python process.py numbers.txt > count.txt
Updating lock file 'dvc.lock'
你现在可以验证 dvc.lock
和 count.txt
是否已更新为新信息:依赖/输出文件的哈希值已更新,以及生成了新的结果。
示例:从目标阶段向下游执行
本示例延续前面的例子。
当与某个 target
阶段一起使用时,--downstream
选项允许我们仅重新执行该特定阶段之后的命令。为了演示其工作方式,我们先修改 text.txt
(即第一个阶段的输入文件,由前一个示例创建):
...
The answer to universe is 42
- The Hitchhiker's Guide to the Galaxy
假设我们还想在描述中打印文件名,因此我们将 process.py
更新为:
print(f'Number of lines in {sys.argv[1]}:')
print(num_lines)
现在,在 dvc repro
中使用 --downstream
选项,只会执行目标阶段(count
)及其后续阶段(本例中无后续阶段):
$ dvc repro --downstream count
Running stage 'count' with command:
python process.py numbers.txt > count.txt
Updating lock file 'dvc.lock'
对 text.txt
的更改被忽略,因为该文件是 filter
阶段的依赖项,而上述 dvc repro
并未执行该阶段。这是因为在管道中,filter
发生在目标阶段(count
)之前(参见 dvc dag
),如下所示:
$ dvc dag
+--------+
| filter |
+--------+
*
*
*
+-------+
| count |
+-------+
请注意,在上述示例中,如果不使用
--downstream
而直接运行dvc repro
,则不仅会执行目标阶段(count
),还会执行其前面的所有阶段(本例中只有 'filter')。
示例:仅按需拉取管道数据
你可以结合使用 --pull
和 --allow-missing
标志,在重现实验管道的同时,仅拉取实际需要的数据来运行已更改的阶段。
基于 example-get-started-experiments 中使用的管道:
$ dvc dag
+--------------------+
| data/pool_data.dvc |
+--------------------+
*
*
*
+------------+
| data_split |
+------------+
** **
** **
* **
+-------+ *
| train |* *
+-------+ **** *
* *** *
* **** *
* ** *
+-----------+ +----------+
| sagemaker | | evaluate |
+-----------+ +----------+
如果我们处于一台所有数据均缺失的机器上:
$ dvc status
data_split:
changed deps:
deleted: data/pool_data
changed outs:
not in cache: data/test_data
not in cache: data/train_data
train:
changed deps:
deleted: data/train_data
changed outs:
not in cache: models/model.pkl
not in cache: models/model.pth
not in cache: results/train
evaluate:
changed deps:
deleted: data/test_data
deleted: models/model.pkl
changed outs:
not in cache: results/evaluate
sagemaker:
changed deps:
deleted: models/model.pth
changed outs:
not in cache: model.tar.gz
data/pool_data.dvc:
changed outs:
not in cache: data/pool_data
我们可以修改 evaluate
阶段,DVC 将仅拉取运行该阶段所需的必要数据(models/model.pkl
和 data/test_data/
),并跳过其余阶段:
$ dvc repro --pull --allow-missing
'data/pool_data.dvc' didn't change, skipping
Stage 'data_split' didn't change, skipping
Stage 'train' didn't change, skipping
Running stage 'evaluate':
...
更多详情请参阅用户指南中的 拉取缺失数据。