4. 版本控制基础
在模型研发中,“版本”从来不是单一维度。代码在变、超参数在变、训练数据在变、模型权重也在变。如果只用一个 Git 仓库管理全部内容,很快就会遇到大文件膨胀、复现困难、模型与参数对不上号等问题。本节要建立的核心认知是:不同性质的资产,需要由不同工具承担版本管理职责,再通过标识符把它们串成一条可追溯的链路。
一、核心原理:四类工具的分工边界
Git、DVC、MLflow 与模型注册表并非互相替代,而是分别解决“代码与配置”“数据与模型文件”“实验运行记录”“模型生命周期状态”四类问题。理解它们的分工,是搭建一致性审计体系的前提。
| 工具 | 管理对象 | 版本标识 | 在一致性审计中的作用 |
|---|---|---|---|
| Git | 代码、配置、参数文件、DVC 指针文件 | commit SHA | 锁定代码与参数定义,作为审计的根锚点 |
| DVC | 数据集、特征文件、模型权重等大文件 | 内容哈希(.dvc 文件) | 保证数据与模型文件可复现、可校验 |
| MLflow | 实验运行、参数、指标、产物路径 | run_id | 记录每次训练的参数与代码版本关联 |
| 模型注册表 | 模型版本、阶段、审批状态 | 模型名 + 版本号 | 管理上线模型与代码、参数的对应关系 |
可以看到,Git 提供的是“代码坐标”,DVC 提供的是“数据与权重坐标”,MLflow 提供的是“实验坐标”,模型注册表提供的是“交付坐标”。审计的本质,就是验证这四个坐标是否指向同一个真实状态。
二、方法流程:从一次训练到可审计记录
下面用一个典型训练流程说明各工具如何协同。假设我们使用 Git 管理代码,DVC 管理数据,MLflow 记录实验。
# 1. 固定代码与参数版本
git add train.py configs/params.yaml
git commit -m "exp: lr=0.001, batch=64"
# 得到 commit SHA: a1b2c3d
# 2. 确认数据版本
dvc add data/raw/train.csv
git add data/raw/train.csv.dvc
git commit -m "data: freeze train set v3"
# .dvc 文件中记录 md5: 9f8e7d...
# 3. 启动训练并记录到 MLflow
mlflow run . -P learning_rate=0.001 -P batch_size=64 \
--experiment-name recsys \
--run-name "lr0.001-b64"
# MLflow 自动记录 run_id: r-2024-001
训练完成后,MLflow 的 run 中应包含以下关键信息:
- 参数:learning_rate、batch_size 等,与 Git 中的 params.yaml 一致;
- 代码版本:通过 mlflow.set_tag("git_commit", "a1b2c3d") 写入;
- 数据版本:通过 mlflow.set_tag("dvc_md5", "9f8e7d...") 写入;
- 模型产物:artifact 路径或 DVC 指针。
当模型通过评估后,再将其注册到模型注册表,并绑定对应的 run_id 与 commit SHA。这样,任何一个上线模型都能反向追溯到确切的代码、参数和数据版本。
关键原则:MLflow 的 run 是“连接器”,它本身不存储代码和数据,而是通过 tag 和 artifact 把 Git commit、DVC 哈希、模型文件关联起来。审计时只需检查这些关联字段是否完整且一致。
三、可视化:参数与代码版本的一致性链路
下图展示了从代码提交到模型注册的版本关联结构。每个节点代表一个版本载体,连线代表引用关系。审计时沿着连线逐段校验,即可定位断点。
四、案例与场景:一次参数漂移的复盘
某推荐模型在线上效果突然下降。排查发现,模型注册表中 Production 版本对应的 MLflow run 记录的 learning_rate 是 0.01,但 Git 仓库中该 commit 的 params.yaml 写的是 0.001。进一步检查发现,训练时有人手动修改了本地参数文件,却没有提交到 Git,导致 MLflow 记录的是实际运行值,而 Git 记录的是旧值。
这个案例暴露了两个问题:一是参数没有强制从 Git 读取,二是 MLflow 的 git_commit tag 没有在训练时自动写入。修复方案如下:
- 训练脚本启动时强制校验工作区是否干净,若有未提交修改则拒绝训练;
- 使用 MLflow 自动记录 Git commit,例如通过 mlflow.set_tag 或集成 gitpython;
- 在模型注册表审批环节增加“参数一致性检查”,比对 run 参数与 Git 中 params.yaml 的差异。
常见误区:认为“MLflow 记录了参数,就不需要 Git 了”。实际上 MLflow 记录的是运行时值,无法证明该值来自哪份代码。没有 Git commit 锚定,参数就失去了可复现的上下文。
五、误区与复盘清单
在实际审计中,以下问题反复出现,建议作为检查清单使用:
- 只提交代码不提交参数文件:params.yaml 未纳入 Git,导致参数无版本;
- DVC 指针未提交:数据换了但 .dvc 文件没更新,复现时拿到旧数据;
- MLflow run 缺少 git_commit tag:无法从实验反查代码版本;
- 模型注册表版本与 run_id 脱钩:上线模型找不到对应的训练记录;
- 手动修改生产参数:绕过版本控制,造成代码与运行状态不一致。
复盘建议:把“commit SHA + DVC md5 + run_id + 模型版本号”视为一个四元组,任何一次模型交付都必须完整记录该四元组。审计时按四元组逐项核对,即可快速判断一致性是否被破坏。
总结来说,Git 管代码与参数定义,DVC 管数据与权重文件,MLflow 管实验运行记录,模型注册表管交付状态。四者通过 commit SHA、内容哈希和 run_id 相互引用,形成一条可验证的版本链路。只有这条链路完整且一致,模型参数与代码的版本审计才有可靠依据。