
本文较长5000字建议先收藏再阅读。如果你的 ML 项目还在用 jupyter U盘拷贝数据 微信发模型这篇文章就是你的救命稻草。一句话概括MLOps 把 ML 项目当 DevOps 一样管理。代码、数据、实验、模型全版本化全流程自动化。目录一、MLOps到底是什么和DevOps有什么不同传统 ML 项目 vs MLOps 项目一个血淋淋的案例二、MLOps五大环节全景图五大环节的对应工具三、DVC让数据集像代码一样版本化3.1 为什么需要 DVC3.2 DVC 实战3.3 数据版本切换3.4 数据 PipelineDAG四、MLflow Tracking实验跟踪的瑞士军刀4.1 MLflow 三大组件4.2 Tracking 集成示例4.3 MLflow UI 效果4.4 Tracking 的关键收益五、MLflow Model Registry模型全生命周期管理5.1 Model Registry 核心概念5.2 模型注册实战5.3 模型阶段流转5.4 命令行操作六、CI/CD流水线从代码提交到模型上线6.1 完整 MLOps 流水线6.2 GitHub Actions 配置6.3 部署脚本七、完整实战案例从数据准备到生产部署八、避坑指南MLOps的7个真实坑一、MLOps到底是什么和DevOps有什么不同很多团队以为 MLOps ML DevOps错真正的 MLOps 是把 ML 的特殊环节数据、实验、模型也纳入 DevOps 体系。传统 ML 项目 vs MLOps 项目维度传统 ML 项目MLOps 项目代码管理GitGit数据管理共享盘/U盘DVC/Delta Lake版本化实验跟踪Excel 记录MLflow Tracking自动模型管理文件服务器Model Registry注册部署方式手动 SSHCI/CD Seldon自动监控没有Prometheus Grafana协作“谁动了我的数据”可追溯、可回滚一个血淋淋的案例graph TD A[2024年1月br/小王训练了模型 v1br/acc85%] -- B[模型文件丢在br//home/xiaowang/models/] B -- C[小王离职] C -- D[2024年6月br/新数据来了] D -- E[小李重新训练br/acc87%] E -- F[上线后用户反馈br/效果反而变差] F -- G[查不清楚 v1 和 v2br/到底用了什么数据] G -- H[ 翻车] style A fill:#FF6B6B,color:#fff style H fill:#FF6B6B,color:#fffMLOps 的核心价值让 ML 项目的每一步都可追溯、可复现。传统 ML 项目管理就像传话游戏——A 跟 B 说用某数据训练B 跟 C 说用某参数C 跟 D 说部署到某机器传到第 5 个人就完全失真了。MLOps 就是给每句话录音。二、MLOps五大环节全景图graph LR A[1. 数据版本管理br/DVC] -- B[2. 实验跟踪br/MLflow] B -- C[3. 模型注册br/MLflow Registry] C -- D[4. 模型部署br/Seldon Core] D -- E[5. 模型监控br/Prometheus Grafana] E -.-|反馈| A style A fill:#4ECDC4,color:#fff style B fill:#95E1D3,color:#000 style C fill:#FFD93D,color:#000 style D fill:#6BCB77,color:#fff style E fill:#FF6B6B,color:#fff五大环节的对应工具环节推荐工具替代方案数据版本DVCDelta Lake、Pachyderm实验跟踪MLflow TrackingWeights Biases、Neptune模型注册MLflow RegistryBentoML、Harbor模型部署Seldon CoreKFServing、BentoML监控Prometheus GrafanaEvidently AI、Whylabs三、DVC让数据集像代码一样版本化3.1 为什么需要 DVCGit 适合代码但不适合大文件数据集通常是 GB 级别。# 错误示范把数据提交到 Git git add data.csv # 报错file too large (100MB) git push # 推送 5GB 数据网速哭了DVC 的解法代码→ Git 管理数据→ DVC 管理数据存到 S3/OSS/本地Git 里只存数据指纹.dvc文件graph LR A[训练代码br/train.py] -- B[Git 仓库] C[数据集br/data.csv (5GB)] -- D[DVC 远程存储br/S3/OSS/MinIO] E[数据指纹文件br/data.csv.dvc (1KB)] -- B style A fill:#95E1D3,color:#000 style C fill:#FF6B6B,color:#fff style E fill:#FFD93D,color:#000 style B fill:#4ECDC4,color:#fff style D fill:#95E1D3,color:#0003.2 DVC 实战# 1. 安装 DVC pip install dvc dvc-s3 # 2. 初始化项目根目录 git init dvc init # 3. 配置远程存储 dvc remote add -d myremote s3://my-bucket/dvc-storage # 或用阿里云 OSS dvc remote add -d myremote oss://my-bucket/path # 4. 添加数据到 DVC dvc add data/raw.csv # 生成 data/raw.csv.dvc 文件 # 5. 提交到 Git git add data/.gitignore data/raw.csv.dvc git commit -m Add raw dataset v1 # 6. 推送数据到远程存储 dvc push3.3 数据版本切换# 查看数据历史 dvc log data/raw.csv # 切换到 v1 数据 git checkout v1-tag dvc checkout # 切换到 v2 数据 git checkout v2-tag dvc checkout3.4 数据 PipelineDAG# dvc.yaml - 数据 训练 Pipeline stages: prepare: cmd: python src/prepare.py deps: - data/raw.csv outs: - data/processed.csv train: cmd: python src/train.py deps: - data/processed.csv - src/train.py params: - lr - batch_size metrics: - metrics.json: cache: false outs: - models/model.pkl# 一键跑完整 Pipeline dvc repro # 可视化 Pipeline dvc dagDVC 像不像厨房的食材管理系统——Git 是菜谱不会变DVC 是冰箱里的食材每周不一样。菜谱调用哪个食材就用哪个版本。三个月后再做同一道菜味道一模一样。四、MLflow Tracking实验跟踪的瑞士军刀4.1 MLflow 三大组件graph TD A[MLflow] -- B[MLflow Trackingbr/实验记录] A -- C[MLflow Projectsbr/打包运行] A -- D[MLflow Modelsbr/模型格式] A -- E[MLflow Model Registrybr/模型注册中心] style B fill:#4ECDC4,color:#fff style C fill:#95E1D3,color:#000 style D fill:#FFD93D,color:#000 style E fill:#FF6B6B,color:#fff4.2 Tracking 集成示例import mlflow import mlflow.pytorch import torch from torch import nn, optim # 设置 Tracking URI如果用远程 MLflow Server mlflow.set_tracking_uri(http://mlflow-server:5000) mlflow.set_experiment(image-classification) with mlflow.start_run(run_nameresnet50-baseline): # 1. 记录超参数 mlflow.log_param(lr, 0.001) mlflow.log_param(batch_size, 64) mlflow.log_param(optimizer, Adam) mlflow.log_param(epochs, 10) mlflow.log_param(model, resnet50) # 2. 训练循环 for epoch in range(10): # ... 训练代码 ... train_loss ... val_loss ... val_acc ... # 3. 记录每个 epoch 的指标 mlflow.log_metric(train_loss, train_loss, stepepoch) mlflow.log_metric(val_loss, val_loss, stepepoch) mlflow.log_metric(val_acc, val_acc, stepepoch) # 4. 记录最终模型 mlflow.pytorch.log_model(model, model) # 5. 记录额外文件如训练曲线图、混淆矩阵 mlflow.log_artifact(confusion_matrix.png) mlflow.log_artifact(training_curve.png) # 6. 记录环境信息 import sklearn mlflow.set_tag(sklearn_version, sklearn.__version__)4.3 MLflow UI 效果启动 MLflow Tracking Server# 后端用 SQLite元数据存数据库 mlflow server \ --backend-store-uri sqlite:///mlflow.db \ --default-artifact-root s3://my-bucket/mlflow-artifacts \ --host 0.0.0.0 \ --port 5000打开http://localhost:5000你可以看到graph LR A[MLflow UI] -- B[实验列表br/30 个 run] A -- C[对比视图br/acc vs lr] A -- D[单 run 详情br/超参/指标/工件] A -- E[模型版本br/v1 / v2 / v3] style A fill:#FF6B6B,color:#fff style C fill:#4ECDC4,color:#fff4.4 Tracking 的关键收益维度没用 MLflow用了 MLflow超参记录手写 Excel自动记录指标对比翻历史文件UI 一键对比模型管理散落各处文件集中管理可复现性“我记得好像用 lr0.001”准确记录协作“小王又改了我的超参”每个人独立 runMLflow Tracking 像不像实验室的实验记录本——老师要求每一步都写下来签字画押。你以为很烦挂科的时候才知道救命。五、MLflow Model Registry模型全生命周期管理5.1 Model Registry 核心概念graph LR A[MLflow Runbr/一次实验] -- B[Registered Modelbr/注册模型] B -- C[Model Version v1] B -- D[Model Version v2] B -- E[Model Version v3] C --|Stage: None| F[阶段流转] C --|Stage: Staging| F D --|Stage: Production| F E --|Stage: Archived| F style B fill:#FF6B6B,color:#fff style F fill:#4ECDC4,color:#fff5.2 模型注册实战import mlflow from mlflow.tracking import MlflowClient client MlflowClient() # 1. 注册模型 result mlflow.register_model( model_uriruns:/abc123/model, # 某次 run 的 model nameimage-classifier ) # 2. 给模型加描述和标签 client.update_model_version( nameimage-classifier, versionresult.version, descriptionResNet50, trained on 2024-Q1 dataset, acc0.92 ) # 3. 推动模型到 Staging client.transition_model_version_stage( nameimage-classifier, versionresult.version, stageStaging ) # 4. 测试通过后推动到 Production client.transition_model_version_stage( nameimage-classifier, versionresult.version, stageProduction, archive_existing_versionsTrue # 把旧版本归档 )5.3 模型阶段流转stateDiagram-v2 [*] -- None: 注册 None -- Staging: 准备测试 Staging -- Production: 测试通过 Staging -- Archived: 测试失败 Production -- Archived: 新模型上线 Archived -- [*] note right of Staging 在 staging 环境验证 性能/准确率/兼容性 end note note right of Production 线上服务使用 监控告警 end note5.4 命令行操作# 列出所有注册的模型 mlflow models list # 查看特定模型的版本 mlflow models list --name image-classifier # 推动版本到 Production mlflow models transition-stage \ --name image-classifier \ --version 3 \ --stage Production六、CI/CD流水线从代码提交到模型上线6.1 完整 MLOps 流水线graph LR A[开发者 push 代码] -- B[GitHub Actionsbr/CI 触发] B -- C[运行测试] C -- D[DVC 拉取最新数据] D -- E[MLflow Trackingbr/训练模型] E -- F[自动评估指标] F --|acc 阈值| G[注册到 Registry] F --|acc 阈值| H[❌ 失败通知] G -- I[推动到 Staging] I -- J[Seldon Corebr/自动部署到 Staging] J -- K[集成测试] K --|通过| L[推动到 Production] L -- M[Seldon Corebr/自动部署到生产] M -- N[线上服务] style A fill:#FF6B6B,color:#fff style G fill:#4ECDC4,color:#fff style N fill:#6BCB77,color:#fff6.2 GitHub Actions 配置# .github/workflows/ml-pipeline.yml name: ML Training Pipeline on: push: branches: [main] paths: - src/** - data/** - configs/** jobs: train-and-deploy: runs-on: [self-hosted, gpu] # 自托管 GPU runner steps: - name: Checkout code uses: actions/checkoutv3 - name: Setup Python uses: actions/setup-pythonv4 with: python-version: 3.10 - name: Install dependencies run: | pip install -r requirements.txt pip install dvc dvc-s3 mlflow - name: Pull data with DVC run: | dvc pull - name: Run training with MLflow env: MLFLOW_TRACKING_URI: http://mlflow-server:5000 run: | python src/train.py - name: Check metrics threshold run: | python scripts/check_metrics.py --min-acc 0.85 - name: Register model to MLflow run: | python scripts/register_model.py - name: Deploy to Staging with Seldon if: success() run: | python scripts/deploy.py --env staging - name: Integration tests run: | python tests/integration_test.py - name: Deploy to Production if: success() run: | python scripts/deploy.py --env production6.3 部署脚本# scripts/deploy.py import argparse import mlflow from mlflow.tracking import MlflowClient from kubernetes import client, config import yaml def deploy_to_seldon(model_name, model_version, namespaceseldon): 用 Seldon Core 部署模型到 K8s config.load_kube_config() # 从 MLflow Registry 获取模型 client_mlflow MlflowClient() model_uri fmodels:/{model_name}/{model_version} # 生成 SeldonDeployment YAML seldon_spec { apiVersion: machinelearning.seldon.io/v1, kind: SeldonDeployment, metadata: { name: model_name, namespace: namespace }, spec: { predictors: [{ name: default, replicas: 3, graph: { name: classifier, type: MODEL, model: { uri: model_uri, name: ImageClassifier } } }] } } # 应用到 K8s with open(/tmp/seldon_deployment.yaml, w) as f: yaml.dump(seldon_spec, f) k8s_api client.CustomObjectsApi() k8s_api.create_namespaced_custom_object( groupmachinelearning.seldon.io, versionv1, namespacenamespace, pluralseldondeployments, bodyseldon_spec ) print(f✅ Model {model_name}:{model_version} deployed to {namespace}) if __name__ __main__: parser argparse.ArgumentParser() parser.add_argument(--env, choices[staging, production], requiredTrue) parser.add_argument(--model-name, defaultimage-classifier) args parser.parse_args() # 从 MLflow Registry 获取 Production 阶段模型 client_mlflow MlflowClient() versions client_mlflow.get_latest_versions( args.model_name, stages[Production] ) if not versions: print(❌ No Production model found) exit(1) model_version versions[0].version namespace seldon- args.env deploy_to_seldon(args.model_name, model_version, namespace) # 推动模型阶段 client_mlflow.transition_model_version_stage( nameargs.model_name, versionmodel_version, stageProduction if args.env production else Staging ) print(f✅ Model {args.model_name}:{model_version} promoted to {args.env})七、完整实战案例从数据准备到生产部署7.1 案例背景我们要训练一个图像分类模型全流程跑通 MLOps。7.2 项目结构image-classifier/ ├── .dvc/ # DVC 配置 ├── .github/ │ └── workflows/ │ └── ml-pipeline.yml # CI/CD 配置 ├── data/ │ ├── raw.csv.dvc # 数据版本指针 │ └── .gitignore ├── src/ │ ├── prepare.py # 数据准备 │ ├── train.py # 训练 │ └── evaluate.py # 评估 ├── models/ # 训练好的模型 ├── configs/ │ └── config.yaml # 超参配置 ├── scripts/ │ ├── register_model.py │ └── deploy.py ├── tests/ │ └── integration_test.py ├── dvc.yaml # DVC Pipeline ├── params.yaml # 超参 └── requirements.txt7.3 关键代码params.yamllr: 0.001 batch_size: 64 epochs: 10 model: resnet50src/train.pyimport yaml import mlflow import mlflow.pytorch import torch from torch import nn, optim from torch.utils.data import DataLoader from torchvision import datasets, transforms, models def main(): # 1. 加载超参 with open(params.yaml) as f: params yaml.safe_load(f) # 2. 启动 MLflow Run with mlflow.start_run(): mlflow.log_params(params) # 3. 数据加载 transform transforms.Compose([ transforms.Resize(224), transforms.ToTensor(), ]) train_data datasets.ImageFolder(data/train, transformtransform) val_data datasets.ImageFolder(data/val, transformtransform) train_loader DataLoader(train_data, batch_sizeparams[batch_size], shuffleTrue) val_loader DataLoader(val_data, batch_sizeparams[batch_size]) # 4. 模型 if params[model] resnet50: model models.resnet50(pretrainedTrue) else: model models.resnet18(pretrainedTrue) model.fc nn.Linear(model.fc.in_features, 10) criterion nn.CrossEntropyLoss() optimizer optim.Adam(model.parameters(), lrparams[lr]) # 5. 训练 for epoch in range(params[epochs]): model.train() for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() # 验证 model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in val_loader: outputs model(images) _, predicted outputs.max(1) total labels.size(0) correct predicted.eq(labels).sum().item() val_acc correct / total mlflow.log_metric(val_acc, val_acc, stepepoch) print(fEpoch {epoch1}: val_acc{val_acc:.4f}) # 6. 记录最终模型 mlflow.pytorch.log_model(model, model) mlflow.log_metric(final_val_acc, val_acc) if __name__ __main__: main()scripts/register_model.pyimport mlflow from mlflow.tracking import MlflowClient client MlflowClient() experiment client.get_experiment_by_name(image-classification) # 找出最佳 run runs client.search_runs( experiment_ids[experiment.experiment_id], order_by[metrics.final_val_acc DESC], max_results1 ) best_run runs[0] print(fBest run: {best_run.info.run_id}, acc{best_run.data.metrics[final_val_acc]:.4f}) # 注册到 Registry model_uri fruns:/{best_run.info.run_id}/model result mlflow.register_model(model_uri, image-classifier) print(fRegistered as version {result.version})7.4 端到端流程演示# 1. 开发者提交代码 git add . git commit -m feat: add new training config git push origin main # 2. GitHub Actions 自动触发 # - 拉取数据 (dvc pull) # - 训练模型 (python src/train.py) # - 评估指标 # - 注册到 MLflow # - 部署到 Staging # - 集成测试 # - 部署到 Production # 3. 查看 MLflow UI open http://mlflow-server:5000 # 4. 监控生产服务 kubectl get seldondeployments完整的 MLOps 流水线就像全自动厨房——你提交点单请求代码厨房自动选食材数据、备菜准备、炒菜训练、摆盘部署上桌生产。你只管吃不用关心厨房怎么运作。八、避坑指南MLOps的7个真实坑坑 1DVC 远程存储访问失败症状dvc push报AccessDenied原因S3/OSS 的 AccessKey 权限不够解法# 配置正确的 access key dvc remote modify myremote access_key_id YOUR_KEY dvc remote modify myremote secret_access_key YOUR_SECRET坑 2MLflow Tracking Server 启动失败症状Address already in use原因5000 端口被占用解法# 改用其他端口 mlflow server --port 5001坑 3CI 训练速度比本地慢 10 倍症状本地 1 小时训练完CI 跑了 10 小时。原因CI 用的是普通 runner没有 GPU。解法# 用 self-hosted GPU runner runs-on: [self-hosted, gpu]坑 4模型注册后找不到症状mlflow.register_model报No model with name X原因没有先创建 registered model解法# 先用 mlflow.create_registered_model 创建 client MlflowClient() try: client.create_registered_model(image-classifier) except Exception: pass # 已存在 result client.create_model_version( nameimage-classifier, sourceruns:/abc/model, run_idabc )坑 5Seldon 部署后模型加载慢5-10 分钟症状SeldonDeployment 创建成功但 pod 一直 NotReady。原因模型文件大从 S3 拉取慢。解法spec: predictors: - name: default componentSpecs: - spec: containers: - name: classifier resources: requests: memory: 16Gi # 给足内存加载大模型 limits: memory: 32Gi坑 6MLOps 工具版本冲突症状mlflow 2.x和dvc 3.x不兼容。原因版本不匹配。解法# 固定版本 pip install mlflow2.10.0 dvc3.30.0坑 7数据科学家不愿意用 MLOps症状团队成员继续用 jupyter不写 MLflow 代码。原因学习曲线 嫌麻烦。解法培训 强制把 MLOps 工具使用写进代码规范给样板提供写好的train.py模板奖励机制用 MLOps 的人绩效加分⚠️避坑警告MLOps 工具是手段不是目的。别为了用 MLOps 而用 MLOps先解决协作和复现的痛点再上工具。九、总结与下篇预告MLOps 落地路线图graph TD A[阶段1: 手动管理br/Jupyter U盘] --|痛了| B[阶段2: 引入 Git DVC] B --|继续痛| C[阶段3: 引入 MLflow] C --|模型上线难| D[阶段4: 引入 Seldon Core] D --|运维难| E[阶段5: 完整 MLOps 体系] E -- F[数据/实验/模型/部署br/全自动化] style A fill:#FF6B6B,color:#fff style F fill:#6BCB77,color:#fff关键 takeawayMLOps 核心是可复现——让 3 个月前的实验能精确复现DVC 管数据、MLflow 管实验、Seldon 管部署——三大件分工明确CI/CD 是 MLOps 的骨架——没有自动化流水线就不是 MLOpsMLflow Model Registry 让模型有生命周期——Stage 流转是核心别一上来就铺全套——先从 DVC MLflow 开始下篇预告第 25 篇《成本优化——Spot混合云共享GPU省钱三板斧》GPU 太贵用不起Spot 实例省 90% MIG 切分 模型量化AI 推理成本直接砍 80%。老板再也不用担心账单。 文末三件套【源码获取】关注此公众号后台回复「MLOps」获取本文完整项目模板GitHub 仓库 CI/CD 配置 部署脚本。【思考题】你的团队训练了一个模型acc0.92 上了生产。3 个月后数据漂移acc 跌到 0.85。怎么用 MLOps 体系快速回滚到上一个好版本需要哪些前置条件欢迎在评论区分享你的方案。【系列文章预告】✅ 24 篇MLOps 全流程——从数据版本到模型注册本文⏭️ 25 篇成本优化——Spot混合云共享 GPU⏭️ 26 篇腾讯云TCE银行AI架构深度拆解⏭️ 27 篇阿里云ACK医疗AI——安全沙箱网络策略⏭️ 28 篇AI Agent 上 K8s——工具服务容器化标签#MLOps#DVC#MLflow#Seldon#CI/CD#模型注册#实验跟踪