版本控制基础:Git和DVC
说起版本控制,你可能第一反应就是 Git。没错,Git 在我们这行绝对是标配。但做 AI 训练,光有 Git 还不够。你想想看,一个大模型动辄几十 GB,Git 根本管不了。这就引出了今天的主角——Git 和 DVC。
我个人习惯把这两者看作一对搭档。Git 管代码,DVC 管数据和模型。各司其职,缺一不可。我带团队时发现,很多人只记命令,不理解底层逻辑。结果一出问题就抓瞎。今天咱们就把它讲透。
为什么非要用 Git?
Git 的核心价值,说白了就是「后悔药」。做实验改参数,加新模块,改训练策略…… 改来改去,你怎么知道哪个版本跑出了最好结果?没有 Git,你就只能在文件后面加 v1、v2、final、final_v3 这种后缀。别笑,我真见过。
我在一个老项目中遇到过这种事:一个关键实验跑了三天,结果因为没记版本,到汇报时谁也说不清用的是哪份代码。最后只能重跑。嗯,从那以后我强制所有人必须用 Git 打 tag 做版本锁定。
Git 的基本工作流
你不需要背所有命令。记住最核心的几个就好:
git init # 初始化仓库
git add . # 暂存修改
git commit -m "msg" # 提交版本
git tag v1.0.0 # 打标签锁定版本
git checkout v1.0.0 # 切换到指定版本
关键技巧:每次训练前先 git tag,训练后不改代码直接打新 tag。这样每个实验都有唯一对应版本。
我觉得大多数人学 Git 时都犯过一个错:只记 add 和 commit,忽略了分支和 tag。但你想想看,要复现一个三个月前的实验结果,没有 tag 怎么找?翻 commit log 一条条看?那不现实。
Git 的底层逻辑——懂这点就够了
Git 存储的是文件的快照。每次 commit 都是一张照片。不是记录差异,是拍下整个目录的样子。所以每次 commit 都保存了代码全貌。这让你可以任意跳转版本。
这里要注意一个「坑」:Git 对二进制文件很无力。数据集、模型权重这些文件,Git 把你仓库撑爆。我亲眼见过有人把 50GB 的数据集推到 Git 仓库,结果拉代码要等半天。
避坑指南:在 .gitignore 里加上 *.pth、*.h5、data/ 这些规则。数据文件千万别进 Git。
# .gitignore 示例
*.pth
*.pt
*.h5
*.onnx
*.bin
data/
saved_models/
__pycache__/
Git 的常用场景和命令
| 场景 | 命令 | 说明 |
|---|---|---|
| 查看历史 | git log --oneline | 简洁版提交记录 |
| 回滚文件 | git checkout -- file | 撤销未暂存的修改 |
| 回滚提交 | git reset --hard HEAD~1 | 退回上一个版本 |
| 创建分支 | git branch exp-01 | 开新实验分支 |
| 查看差异 | git diff v1.0.0 v2.0.0 | 对比两版本改了啥 |
我曾经吃过这个亏:用 git reset --hard 之前没看清楚,直接把一周的工作丢了。建议多用 git stash 暂存。命令:git stash save "xxx"。
为什么要加上 DVC?
Git 管不了大文件这件事,不是 Git 的错。它本就不是为这个设计的。做 AI 训练,你需要数据版本控制。DVC 就是干这个的。
DVC 的思路很巧妙:它不存文件本身,而是存文件的「指针」和「哈希值」。你把大型数据放到云存储或 NAS 上,DVC 只记下它在哪、哈希是多少。代码库就只存了一个 tiny 指针文件。每次 git commit、git checkout,这个指针文件跟着走,对应的数据文件自动同步。
核心概念:DVC 的 .dvc 文件只有几百字节,相当于一个书签。Git 管理书签,DVC 管理真正的书。
DVC 的基本使用流程
第一步:初始化 DVC。
pip install dvc
dvc init # 在Git仓库内初始化
git add .dvc/
git commit -m "init dvc"
第二步:添加数据文件,告诉 DVC 你盯上它了。
dvc add data/train.csv # 生成 data/train.csv.dvc
git add data/.gitignore data/train.csv.dvc
git commit -m "track train.csv with dvc"
第三步:设置远程存储。可以是 S3、GCS、NAS、甚至本地硬盘。
dvc remote add -d myremote /mnt/nfs/shared
dvc push # 上传实际数据
第四步:别人想复现,只需要 pull。
git pull
dvc pull # 自动下载对应版本的数据
提示:DVC 的远程存储可以配置权限隔离。生产环境里,我一般把数据放在公司内部的对象存储上,不让数据出内网。
Git 和 DVC 如何协同工作?
现在你看这张协作图就明白了。Git 管代码仓库,DVC 管数据仓库。每一次实验,Git 锁定代码 + 配置的版本,DVC 锁定数据和模型权重的版本。两者结合,你就能精准复现任何一次训练。
工作流就是:
- 改代码 → git add + git commit
- 改数据 → dvc add + git commit (提交 .dvc 文件)
- 跑完训练 → dvc add 模型权重 + git commit (记录权重版本)
- 打标签 → git tag exp-v3.2
- 回到这个实验 → git checkout exp-v3.2 + dvc checkout
你看,是不是很顺?一旦跑通这个流程,你就不再怕「忘了我用的哪个数据集」这种蠢问题了。我在项目中落地这个流程后,团队少扯了至少一半的皮。
常见错误和避坑指南
- 别把数据集放在 Git 管理的目录外:DVC 只能在 Git 仓库内追踪文件。数据文件得放在项目目录下。
- 别忘记 push:git push 和 dvc push 是两码事。代码提交了,数据没上传,别人还是拉不到。
- 别忘了 .gitignore:数据文件排到 Git 里,不仅冗余,还会让 dvc pull 时出现冲突。
- 小心 .dvc 文件的冲突:多人同时修改同一个数据文件,合并 .dvc 文件时可能冲突。我遇到过,解决方法是手动确认哈希值。
我曾经在项目中没做 dvc push,结果第二天同事 dvc pull 只拿到一个旧版本。从那以后我写了个脚本,每次 git push 之前自动执行 dvc push。再也不忘了。
好,现在你应该清楚 Git 和 DVC 的角色分工了。一个管代码,一个管数据。两者配合,你才能做到真正的版本锁定。后面的章节会讲怎么把这些概念落实到训练参数的锁定上,那时候你会发现,今天的铺垫非常必要。