3、版本控制:Git与DVC(数据版本控制)集成、模型注册表概念、MLflow Model Registry实战

好,咱们进入第三个章节。版本控制这件事,做软件开发的兄弟都不陌生。但模型部署不一样——你不仅要管代码,还得管数据、管模型、管实验配置。我见过太多团队,代码用Git管得挺好,模型文件却散落在各个文件夹里,命名方式千奇百怪:model_final_v3_really_final.pth,你懂的。

这一章,咱们就聊聊怎么把版本控制这件事做透。说白了,就是让Git管代码,让DVC管数据,让MLflow管模型。各司其职,清清楚楚。

3.1 Git与DVC的集成:代码和数据分开管

Git本身不适合管大文件。一个预训练模型动辄几百MB,甚至几个GB。你把它塞进Git仓库,每次clone都像在下载电影。而且Git的diff机制对大文件毫无意义——你改了一个权重参数,Git会认为整个文件都变了。

DVC(Data Version Control)就是来解决这个问题的。它的核心思路很简单:用Git管理元数据,用远程存储管理实际文件

核心思想:DVC会在你的仓库里生成一个 .dvc 文件,这个文件很小,记录了原始文件的哈希值和存储位置。你把这个 .dvc 文件提交到Git,实际的大文件则推送到S3、GCS或者本地NAS上。

我在项目中遇到过一种情况:团队里有人直接把模型文件用Git LFS管理,结果每次拉取代码都要等半小时。后来换成DVC,配合S3存储,速度提升很明显。嗯,这里要注意,DVC不是替代Git,而是Git的补充。

3.1.1 快速上手DVC

安装很简单,一行命令搞定:

pip install dvc

初始化DVC,它会创建一个 .dvc 目录:

cd your-project
git init
dvc init

然后配置远程存储。我个人习惯用S3,但MinIO或者本地路径也行:

dvc remote add -d myremote s3://my-bucket/dvc-store

接下来,把你需要版本控制的数据文件加进来:

dvc add data/raw_dataset.csv
dvc add models/bert_finetuned.pth

这时候你会发现,仓库里多了两个 .dvc 文件。把这两个文件提交到Git:

git add data/raw_dataset.csv.dvc models/bert_finetuned.pth.dvc .dvc/config
git commit -m "Add dataset and model with DVC tracking"

最后,把实际文件推送到远程存储:

dvc push

别人要拉取你的数据时,只需要:

git pull
dvc pull

你看,整个过程跟Git的体验几乎一致。这就是DVC设计得好的地方——学习成本很低。

小技巧:我建议把 dvc pushdvc pull 写到CI/CD流水线里。每次模型训练完,自动推送新版本的数据和模型。这样团队其他人永远能拿到最新版本。

3.2 模型注册表概念:给模型一个「身份证」

模型注册表,说白了就是一个中心化的模型管理平台。它解决什么问题?你想想看,一个项目跑下来,可能产生几十个模型版本。哪个版本效果最好?哪个版本部署到了生产环境?哪个版本有严重的过拟合?如果没有注册表,这些信息全靠口口相传,迟早出乱子。

模型注册表的核心功能包括:

  • 版本管理:每个模型都有唯一的版本号,支持回滚
  • 元数据记录:训练参数、数据集版本、评估指标、创建时间等
  • 阶段标记:标记模型处于哪个阶段——Staging、Production、Archived
  • 权限控制:谁可以注册新模型,谁可以部署到生产

我曾经在一个金融项目里吃过亏。当时模型迭代很快,一周更新两三次。没有注册表,生产环境用的模型版本全靠运维手动记录。有一次回滚,运维搞错了版本号,把还没验证的模型推了上去,结果线上出了半小时的异常。从那以后,我再也不敢不用模型注册表了。

避坑指南:模型注册表不是数据库,它更强调「可追溯」和「可复现」。你注册一个模型,应该能追溯到它对应的代码commit、数据集版本、训练超参数。缺少任何一个环节,这个模型就是「孤儿模型」,出了问题你根本查不到原因。

3.3 MLflow Model Registry实战

MLflow是目前最流行的机器学习生命周期管理工具之一。它的Model Registry模块,正好实现了我们刚才说的模型注册表功能。而且它跟MLflow Tracking天然集成,用起来很顺手。

3.3.1 环境准备

先安装MLflow:

pip install mlflow

启动MLflow服务,我建议用SQLite做后端存储,简单够用:

mlflow server --backend-store-uri sqlite:///mlflow.db --default-artifact-root ./mlruns --host 0.0.0.0 --port 5000

嗯,这里要注意,生产环境建议用PostgreSQL或者MySQL,并发性能更好。

3.3.2 训练并注册模型

咱们用一个简单的例子演示。假设你训练了一个XGBoost模型:

import mlflow
import mlflow.xgboost
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score

# 设置MLflow Tracking URI
mlflow.set_tracking_uri("http://localhost:5000")

# 创建一个实验
mlflow.set_experiment("churn_prediction")

with mlflow.start_run() as run:
    # 训练模型
    model = XGBClassifier(n_estimators=100, max_depth=5)
    model.fit(X_train, y_train)
    
    # 记录参数和指标
    mlflow.log_param("n_estimators", 100)
    mlflow.log_param("max_depth", 5)
    accuracy = accuracy_score(y_test, model.predict(X_test))
    mlflow.log_metric("accuracy", accuracy)
    
    # 记录模型
    mlflow.xgboost.log_model(model, "model")
    
    # 注册模型到Model Registry
    mlflow.register_model(
        model_uri=f"runs:/{run.info.run_id}/model",
        name="ChurnPredictionModel"
    )

运行这段代码后,打开MLflow UI(http://localhost:5000),你会看到:

  • 在「Experiments」页面,能看到这次运行的参数和指标
  • 在「Models」页面,能看到新注册的 ChurnPredictionModel,版本号为1

3.3.3 管理模型版本和阶段

模型注册了,接下来要管理它的生命周期。MLflow支持给每个版本打上阶段标签:

阶段 说明 典型用途
None 未指定阶段 刚注册的模型,还没评估
Staging 预发布阶段 通过单元测试,准备集成测试
Production 生产阶段 已通过所有验证,部署到线上
Archived 归档阶段 已下线,保留历史记录

你可以通过MLflow UI手动调整阶段,也可以用API:

from mlflow.tracking import MlflowClient

client = MlflowClient(tracking_uri="http://localhost:5000")

# 将版本1提升到Staging
client.transition_model_version_stage(
    name="ChurnPredictionModel",
    version=1,
    stage="Staging"
)

# 将版本1提升到Production
client.transition_model_version_stage(
    name="ChurnPredictionModel",
    version=1,
    stage="Production"
)

重要提醒:MLflow默认允许同一个模型有多个版本处于Production阶段。我个人建议在CI/CD脚本里加一个检查——把旧版本自动降级为Archived,确保生产环境只有一个活跃版本。否则部署时容易搞混。

3.3.4 从注册表加载模型进行推理

部署的时候,直接从注册表加载模型,不用关心模型文件存在哪里:

import mlflow.pyfunc

# 加载Production阶段的模型
model = mlflow.pyfunc.load_model(
    model_uri="models:/ChurnPredictionModel/Production"
)

# 进行推理
predictions = model.predict(new_data)

你看,代码里只写了模型名称和阶段。至于模型文件存在S3还是本地,版本号是1还是5,这些细节都被MLflow封装好了。这就是注册表的价值——解耦。

3.3.5 实战中的最佳实践

根据我的经验,有几点值得注意:

  • 命名规范:模型名称用驼峰命名,比如 ChurnPredictionModelFraudDetectionModel。别用中文,也别用空格。
  • 版本号策略:每次注册自动递增,不要手动指定版本号。MLflow会自动处理。
  • 描述信息:注册模型时,用 mlflow.register_modeldescription 参数写上关键信息,比如「基于2024年Q1数据训练,AUC=0.92」。
  • 自动化:把模型注册和阶段转换集成到CI/CD里。比如,模型评估通过阈值后,自动从Staging提升到Production。

一个小技巧:我习惯在模型注册时,同时记录数据集的DVC版本号。这样,如果生产环境模型出了问题,我可以快速回滚到对应的数据集版本,重新训练。这个信息可以写在模型的description里,或者用MLflow的 log_param 记录下来。

好,这一章的内容就到这里。Git管代码,DVC管数据,MLflow管模型——这三者配合起来,你的模型部署工具链就有了坚实的基础。下一章,咱们聊聊容器化,把模型打包成Docker镜像,让它能在任何地方跑起来。