起因
ML 项目的代码可以 git 管,但数据集(几百 MB / 几 GB / 几十 GB)不能进 git。
结果是"我两个月前那个 SOTA 实验用的是哪份数据?" 完全说不清。
git 只能 commit 一个 data.csv 指针 / README 描述,没法保证可复现。
DVC 把这个问题解了:在 git 里只 commit 一个"数据元信息文件"(指针 +
hash),实际数据存对象存储 / S3 / SSH 服务器。dvc pull 拉对应 hash 的
数据,整套实验完全可复现。
解决方案
装
uv add 'dvc[s3]' # 后端用 S3;其它有 [gs] [azure] [ssh] [gdrive]
# 或 brew install dvc
dvc version
初始化
在已有 git 仓库里:
dvc init
git commit -m 'init dvc'
DVC 在 .dvc/ 建配置目录。
配远程存储
dvc remote add -d myremote s3://my-bucket/dvc-storage
dvc remote modify myremote endpointurl https://s3.example.com # 兼容 minio
# AWS S3 凭据走 ~/.aws/credentials 或环境变量
git commit .dvc/config -m 'add s3 remote'
添加数据
dvc add data/train.parquet
# 输出:data/train.parquet.dvc + .gitignore 更新
git add data/train.parquet.dvc data/.gitignore
git commit -m 'add train dataset v1'
# 推送数据到 S3
dvc push
.dvc/cache/ 是本地缓存。data/train.parquet.dvc 文件长这样:
outs:
- md5: 6c7a3b8d9e2f4a1c5b8e7d6f3a2c4b5e
size: 234567890
path: train.parquet
只 28 行 YAML 进 git,原始几百 MB 数据进 S3。
别人 / 别机器拉
git clone my-project
cd my-project
dvc pull
# 自动拉所有 .dvc 文件对应的数据
切某个 git commit → dvc pull 自动拉那个版本的数据。
Pipeline(DAG)
DVC 的核心还在于 pipeline 定义 + 自动 cache。dvc.yaml:
stages:
prep:
cmd: python src/prep.py
deps:
- src/prep.py
- data/raw.parquet
outs:
- data/clean.parquet
train:
cmd: python src/train.py --data data/clean.parquet --out models/model.pt
deps:
- src/train.py
- data/clean.parquet
params:
- lr
- epochs
outs:
- models/model.pt
metrics:
- metrics.json
eval:
cmd: python src/eval.py
deps:
- models/model.pt
- data/test.parquet
metrics:
- eval.json
跑:
dvc repro # 跑全 pipeline,按依赖关系 + 自动跳过未变 stage
dvc repro train # 只跑 train + 下游
dvc dag # 看 DAG
params.yaml:
lr: 0.001
epochs: 10
改 params.yaml 里某个值 → dvc repro 只重跑受影响 stage。
没改的 stage 命中 cache 秒级返回。
实验对比
dvc exp run -S lr=0.005 -S epochs=20
dvc exp run -S lr=0.001 -S epochs=30
dvc exp show
# 表格对比所有实验的 params + metrics
-S 临时改参数。每次 exp 产生独立分支,不污染 main。
效果
- 数据从 git 中消失(仓库从 5 GB 降到 12 MB)
- 切换数据版本 = git checkout + dvc pull,分钟级
- 多人同时改不同 stage 不冲突(每人本地 cache 各自命中)
- "上次 SOTA 用的是哪份数据" 永远答得清
- CI 里
dvc pull+dvc repro复现实验
与 git-lfs / DataLad 对比
| git-lfs | DVC | DataLad | |
|---|---|---|---|
| 数据大文件 | ✅ | ✅ | ✅ |
| Pipeline | ❌ | ✅ | ❌ |
| 实验跟踪 | ❌ | ✅ | ❌ |
| 多 backend | 仅 GitHub LFS | S3 / GCS / SSH / 多 | 多 |
| 学习曲线 | 低 | 中 | 高 |
只存数据用 git-lfs;要做 ML pipeline 用 DVC。
踩过的坑
-
第一次
dvc add大文件慢:要算 md5 + 复制到 .dvc/cache/。
dvc config cache.type symlink用软链不复制,省时省空间但
.dvc/cache/不能跨文件系统。 -
没 push 就 commit + push git:别人
git pull+dvc pull拉不到
数据。养成dvc push在git push前的习惯。 -
.dvc/cache 占满磁盘:本地保留所有版本 + 多分支切换累积。
dvc gc --workspace清掉工作区当前 commit 用不到的;
dvc gc --all-commits极致清。 -
multiple users 写同一 stage:
dvc lock防止并发 repro 撞车。
或者 stage outputs 必须确定,random_seed 要固定。 -
大数据集多人 train:每人都
dvc pull几十 GB 浪费带宽。可以
配 dvc 远程在共享 NFS 上,所有人挂载到本地.dvc/cache/共享,
配 cache.type=symlink。
登录后参与评论。