如何使用DVC追踪依赖流水线输出的文件及多阶段工作流
直接在项目根目录定义dvc.yaml拆分流水线阶段,靠DVC自带的依赖哈希校验机制就能覆盖你的所有需求,不需要额外做复杂的版本绑定逻辑。
流水线阶段基础配置
四个阶段按依赖顺序定义即可,每个阶段明确写清依赖项(deps)和输出项(outs):
- 原始数据获取阶段
命令填你拉取原始视频素材的执行脚本,比如python scripts/fetch_raw_videos.py,依赖包含拉取脚本、数据源地址配置,输出设为data/raw/原始视频目录,DVC会自动计算目录内所有文件的哈希做版本追踪。 - 人脸裁剪块提取阶段
命令填裁剪逻辑脚本,比如python scripts/extract_face_crops.py,依赖项必须包含三个部分:上一阶段的原始视频输出目录、裁剪脚本本身、所有和裁剪逻辑相关的参数(比如裁剪尺寸、人脸检测置信度阈值,统一存在params.yaml里由DVC自动读取),输出设为data/crops/裁剪块目录、以及裁剪块和原视频帧对应关系的元数据文件。 - 人工标注阶段
这个阶段不需要写可自动执行的命令,只需要声明依赖是上一阶段输出的全量裁剪块目录+元数据文件,输出是标注结果文件data/annotations/labels.json,可以加meta字段标记这是人工操作环节。 - 模型训练阶段
命令填训练脚本,比如python scripts/train.py,依赖包含标注结果文件、裁剪块目录、训练脚本、所有训练相关参数(batch size、epoch、随机种子等都放params.yaml),输出设为models/模型权重目录、训练日志目录。
核心顾虑的对应解决方式
上游变更自动触发下游产物失效
DVC的依赖判断逻辑是基于内容哈希的:只要第二阶段的任意依赖发生变化——不管是你调整了params.yaml里的裁剪尺寸、改了裁剪脚本的逻辑、还是上游原始视频变了,第二阶段输出的裁剪块目录哈希就会和之前记录的版本不一致。
你在定义第三、第四阶段时,已经明确把上游阶段的输出设为了自己的依赖,DVC做状态校验时一旦发现上游哈希不匹配,会直接标记标注结果、模型文件为失效状态,执行dvc repro时不会误用旧版本的标注和模型,完全满足级联失效的要求。
注意不要把裁剪块目录加入.gitignore或者DVC的忽略列表,必须让DVC托管这个目录的版本,否则哈希校验不会生效。
人工标注环节的输入可复现保障
人工操作本身不需要满足可复现要求,你只需要做好两点就能保证输入可回溯、可复现:
- 第二阶段的所有输出(裁剪块、元数据)全部纳入DVC追踪,每次启动标注任务前,通过
dvc checkout就能切到对应版本的裁剪块数据集,和当时生成这批裁剪块的内容完全一致,不会因为脚本改动、文件误修改导致输入偏差。 - 标注阶段不需要填
cmd字段,参考配置如下:
stages: annotate: deps: - data/crops/ - data/crops/metadata.json outs: - data/annotations/labels.json meta: type: manual_operation note: 标注完成后手动执行dvc commit提交版本
人工标注完成后,手动执行dvc commit annotate,DVC就会把当前的标注文件哈希、和它依赖的裁剪块版本哈希做绑定,后续只要裁剪块版本不变,你随时可以回溯到当时标注用的准确输入。DVC不会强制要求这个阶段存在可自动执行的复现命令。
含随机因素的训练环节追踪
训练过程的随机性完全不影响DVC的追踪逻辑,不需要为了满足DVC要求强行消除所有随机因素:
DVC的核心作用是追踪「产物和依赖的对应关系」,而不是强制要求相同输入必须生成字节级完全一致的输出。你如果想尽可能降低结果波动,可以把随机种子、框架版本、CUDA配置都写到params.yaml里纳入依赖追踪,但哪怕最后训练出的模型权重因为随机因素和之前跑的结果不一样,只要训练完成后执行dvc commit train,DVC就会把这版模型和它对应的所有依赖(哪批标注数据、哪版裁剪块、哪个版本的训练脚本、什么参数配置)绑定,你随时可以回溯任意版本模型的完整产出链路。
日常改完代码或者参数后,跑一句dvc status就能直接看到哪些下游产物因为上游变更失效,不需要手动维护版本对应表。
内容的提问来源于stack exchange,提问作者Michael Litvin

