AI项目从入门到上线23-代码一推送就自动训练模型?GitHub Actions + ML训练流水线
你写完三行Python训练脚本,手动开GPU服务器,手动配环境,手动跑——跑完发现忘了记录超参数。你的"自动化"就是把手动改成双手操作。今天这篇,教你用GitHub Actions让每次
git push自动触发训练、自动记录结果、自动发告警——你只管写代码,剩下的交给流水线。
目录
一、GitHub Actions + ML训练:这条流水线到底长什么样
二、三套事件触发器:push / PR / release 各司其职
2.1 Push到main → 触发完整训练
2.2 Pull Request → 触发快速验证测试
2.3 Release → 触发部署
三、核心Workflow完整拆解(能直接跑的那种)
Workflow设计要点拆解
四、GPU Runner配置:白嫖Github还是自建算力
4.1 GitHub-hosted Runner:白嫖党首选
4.2 Self-hosted GPU Runner:正经训练的必经之路
4.3 方案对比一图胜千言
五、模型与数据版本管理:DVC + Git LFS双剑合璧
5.1 Git LFS:管大文件
5.2 DVC:管数据版本
六、训练结果自动记录:MLflow无缝集成
七、失败告警:训练崩了别等用户来告诉你
7.1 飞书机器人告警(最推荐,国内友好)
7.2 Slack告警
7.3 钉钉告警
八、CI/CD触发训练完整流程图
九、踩坑与技巧合集
⚠️ 避坑清单
💡 效率技巧
十、总结与系列预告
开篇:你的"自动训练"其实是"手动换了个壳"
先来做个小调查。
你目前的模型训练流程是什么样的?
A. SSH登录GPU服务器 →python train.py→ 盯着终端看loss下降 → 截图存到微信"文件传输助手"
B. 写了个Shell脚本,但还是得手动触发,偶尔忘了source虚拟环境,跑一半炸了
C. 用Jupyter Notebook,训练和调参混在一起,Cell顺序全乱套
如果你的答案是以上任意一种,恭喜——你的所谓的"自动化训练",本质上只是把一只手操作换成了两只手。
真实案例:我和同事合作一个NLP模型项目。他跑一组参数,我跑一组,结果我俩的训练结果用的是不同版本的训练集——因为他在本地改了config.yaml,我拉的最新代码里没有。两组实验数据对不上,开了半小时会才发现:哦,你训练用的是昨天的数据,我用的是今天的数据。
那一刻我就知道,不搞训练流程自动化,迟早被自己坑死。
💡本文是「L5实战——AI DevOps全流程」系列第四篇。建议先读第一篇 [MLflow实验追踪]、第二篇[模型评估与A/B测试]、第三篇[模型服务化]——不过直接读这篇也不影响,我会在必要的地方做关联标注。
一、GitHub Actions + ML训练:这条流水线到底长什么样
先把概念摊开说。
GitHub Actions本质上就是一个事件驱动的自动化执行器。你告诉它"当发生X事件时,在Y环境上依次执行Z这些步骤",它就照做。对于ML训练场景来说——
- X事件= push到main分支、PR提交、打release标签
- Y环境= GPU Runner(你自建的带显卡的机器,或者GitHub提供的CPU-only runner做轻量任务)
- Z步骤= 环境安装 → 数据拉取 → 模型训练 → 结果上传 → 告警通知
这跟传统的"手动SSH上去跑train.py"的差别,就像你自己下楼买菜(传统方式),和盒马下单30分钟送达(GitHub Actions)——流程一样,但后者不需要你亲自操作每一步。
先看一张最简架构图,建立全局认知:
graph TB subgraph "触发层" PUSH["🔵 push/main<br/>触发训练"] PR["🟡 pull_request<br/>触发测试"] REL["🟢 release<br/>触发部署"] end subgraph "编排层 GitHub Actions" WF["📋 Workflow<br/>github-actions[bot]"] YML["train.yml<br/>YAML任务定义"] end subgraph "执行层 Runner" GPU["🖥️ Self-hosted GPU Runner<br/>NVIDIA A10/A100/V100"] CPU["💻 GitHub-hosted Runner<br/>ubuntu-latest"] end subgraph "工具链" DVC["📦 DVC<br/>数据版本"] LFS["🗂️ Git LFS<br/>大模型文件"] MLF["📊 MLflow<br/>实验追踪"] ALERT["🚨 告警通知<br/>飞书/钉钉/Slack"] end PUSH --> YML PR --> YML REL --> YML YML --> WF WF -->|训练任务| GPU WF -->|轻量检查| CPU GPU --> DVC GPU --> LFS GPU --> MLF GPU --> ALERT CPU --> ALERT style PUSH fill:#4a90d9,color:#fff style PR fill:#f0ad4e,color:#fff style REL fill:#27ae60,color:#fff style GPU fill:#e74c3c,color:#fff style WF fill:#9b59b6,color:#fff看懂了吗?很简单:你推代码,它训练;你提PR,它跑测试;你打release,它部署。你唯一要做的动作就是git push,剩下的流水线全自动接管。
二、三套事件触发器:push / PR / release 各司其职
GitHub Actions的触发器(on字段)是整个流水线的"起床闹钟"。ML场景下,最实用的就是这三种:
2.1 Push到main → 触发完整训练
这最常见。你改完代码推到main,流水线启动训练。但问题来了——你每个commit都训练一次,GPU账单受得了吗?
所以需要加paths过滤,只在关键文件变化时触发:
on: push: branches: [main] paths: - 'src/train.py' - 'src/model.py' - 'configs/**' - 'requirements.txt' - 'Dockerfile'💡效率技巧①:paths过滤省GPU钱!别让README的commit触发训练。精准指定触发路径,一个月少花50%的GPU冤枉钱。
2.2 Pull Request → 触发快速验证测试
PR触发的不该是全量训练(太贵),而是快速冒烟测试——跑几个epoch,确认loss能下降、梯度不NaN、代码没崩。
on: pull_request: branches: [main] paths: - 'src/**' - 'configs/**' - 'tests/**'具体做什么:用一个小epoch(比如3个epoch)+ 小batch验证loss曲线正常下降,确认代码逻辑正确。这通常用CPU Runner就行,不用占GPU。
2.3 Release → 触发部署
当你觉得当前模型效果好、想上线时,打个tag推送release,流水线自动做部署。
on: release: types: [published]发布时自动做:模型导出(ONNX/TorchScript) → 推送到模型仓库 → 更新MLflow Staging/Production标签。
三、核心Workflow完整拆解(能直接跑的那种)
好了,理论讲完,上硬菜。下面是一份完整的、能直接跑的训练流水线YAML:
name: 🔄 ML Model Training Pipeline on: push: branches: [main] paths: - 'src/train.py' - 'src/model.py' - 'configs/**' - 'requirements.txt' pull_request: branches: [main] paths: - 'src/**' - 'configs/**' - 'tests/**' release: types: [published] env: PYTHON_VERSION: '3.10' MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }} DVC_REMOTE: ${{ secrets.DVC_REMOTE }} jobs: # ── Job 1: 代码质量检查(PR触发) ── code-check: runs-on: ubuntu-latest if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: { python-version: '${{ env.PYTHON_VERSION }}' } - name: 安装Lint工具 run: pip install ruff mypy - name: 代码格式检查 run: ruff check src/ - name: 类型检查 run: mypy src/ --ignore-missing-imports # ── Job 2: 快速冒烟测试(PR触发,CPU即可) ── smoke-test: runs-on: ubuntu-latest needs: code-check if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: { python-version: '${{ env.PYTHON_VERSION }}' } - name: 安装依赖(CPU版PyTorch) run: | pip install torch --index-url https://download.pytorch.org/whl/cpu pip install -r requirements.txt - name: 3-epoch快速验证 run: | python src/train.py \ --epochs 3 \ --batch-size 16 \ --smoke-test # ── Job 3: 完整训练(push/main触发,跑在GPU Runner上) ── train: runs-on: [self-hosted, gpu] # 🔑 关键:指定GPU Runner needs: [] # 不依赖code-check,并行执行 if: github.event_name == 'push' && github.ref == 'refs/heads/main' timeout-minutes: 480 # 8小时超时,防止死循环烧钱 steps: - uses: actions/checkout@v4 with: lfs: true # 🔑 自动拉取Git LFS文件 - name: 拉取DVC数据 run: | pip install dvc[s3] dvc pull - name: 检查GPU可用性 run: nvidia-smi - name: 安装Python依赖 run: pip install -r requirements.txt - name: 📊 启动MLflow Run id: train_step run: | python src/train.py \ --epochs ${{ vars.TRAIN_EPOCHS || 50 }} \ --batch-size ${{ vars.BATCH_SIZE || 32 }} \ --learning-rate ${{ vars.LEARNING_RATE || 0.001 }} \ --wandb-run-id ${{ github.run_id }} \ --mlflow-experiment "github-actions-training" - name: 上传训练产物 if: always() uses: actions/upload-artifact@v4 with: name: training-artifacts-${{ github.run_id }} path: | outputs/ logs/ mlruns/ # ── Job 4: Release部署(release触发) ── deploy: runs-on: [self-hosted, gpu] if: github.event_name == 'release' needs: [train] steps: - uses: actions/checkout@v4 with: { lfs: true } - name: 模型导出ONNX run: | python src/export.py \ --checkpoint ./outputs/best_model.pt \ --output ./outputs/model.onnx - name: 推送到MLflow Registry run: | python -c " import mlflow mlflow.set_tracking_uri('${{ secrets.MLFLOW_TRACKING_URI }}') client = mlflow.tracking.MlflowClient() # 将最新模型标记为 Production latest = client.search_model_versions( 'name=\"my_model\"' )[-1] client.transition_model_version_stage( name='my_model', version=latest.version, stage='Production' ) print(f'✅ Model v{latest.version} promoted to Production') "Workflow设计要点拆解
上面这个YAML看着长,其实就四个Job,逻辑很清晰:
| Job | 触发条件 | Runner | 干什么 | 耗时 |
|---|---|---|---|---|
code-check | PR | ubuntu-latest (免费) | ruff + mypy | ~1分钟 |
smoke-test | PR | ubuntu-latest (免费) | 3 epoch CPU训练 | ~5分钟 |
train | push/main | self-hosted GPU | 全量训练 | 视数据而定 |
deploy | release | self-hosted GPU | 导出+发布 | ~3分钟 |
⚠️避坑①:
timeout-minutes不设会导致天价GPU账单。GitHub Actions默认超时6小时,如果你设的epoch太多或者卡死在某个step,它会跑满6小时才停。强烈建议根据你的单次训练时间×1.5倍设置。我踩过的坑:凌晨3点训练脚本死循环,到早上8点还在跑,AWS账单直接多出$200。
⚠️避坑②:
needs: []让训练不阻塞在code-check上。默认行为是Job串行执行,如果训练要等code-check跑完,每次push都多等几分钟。用needs: []让它独立并行启动——毕竟代码能不能push到main不是你该在训练前验证的事(应该在PR阶段就拦住)。
四、GPU Runner配置:白嫖Github还是自建算力
这是个灵魂抉择:用GitHub免费提供的Runner(cpu-only),还是自己搭带GPU的Runner?
4.1 GitHub-hosted Runner:白嫖党首选
GitHub免费提供ubuntu-latest/windows-latest/macos-latestRunner。优点:不要钱,开箱即用。缺点:没GPU,硬盘才14GB,你的ResNet-50可能都装不下。
适合PR阶段的代码检查和冒烟测试。
4.2 Self-hosted GPU Runner:正经训练的必经之路
在你有GPU的服务器上装GitHub Actions Runner Agent,把它注册到你的仓库:
# 1. 在GitHub仓库 Settings → Actions → Runners → New self-hosted runner # 2. 在你的GPU服务器上执行(以Linux为例): mkdir actions-runner && cd actions-runner # 下载runner包 curl -o actions-runner-linux-x64.tar.gz -L \ https://github.com/actions/runner/releases/download/v2.319.1/actions-runner-linux-x64-2.319.1.tar.gz tar xzf ./actions-runner-linux-x64.tar.gz # 配置(需要你的repo URL + token) ./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO \ --token YOUR_REGISTRATION_TOKEN \ --labels self-hosted,gpu,linux,a10 \ --name gpu-runner-01 # 启动(后台运行) nohup ./run.sh > runner.log 2>&1 & # 验证 ps aux | grep Runner.Listener💡效率技巧②:给Runner打多标签实现灵活调度。如上例的
self-hosted,gpu,linux,a10四个标签。Workflow里用runs-on: [self-hosted, gpu]可以精确调度到GPU机器。后期多台Runner混用(A100跑大模型、V100跑轻量任务、CPU跑数据处理),靠标签区分,互不抢占。
Runner配置还有个关键点——环境变量要在Runner服务器上预装好。不然每个Workflow都要从头装CUDA、cuDNN,每次多浪费10分钟。
# GPU Runner必备预装检查清单 nvidia-smi # ✅ NVIDIA驱动 ≥ 525 nvcc --version # ✅ CUDA ≥ 11.8 python3 --version # ✅ Python 3.10+ pip install torch torchvision # ✅ PyTorch GPU版预装 pip install mlflow dvc[s3] # ✅ 常用工具预装4.3 方案对比一图胜千言
| 维度 | GitHub-hosted | Self-hosted GPU |
|---|---|---|
| GPU | ❌ 没有 | ✅ A10/A100/V100 |
| 费用 | 🆓 免费(公开仓库) | 💰 服务器成本 |
| 存储 | 14GB | 你想多大就多大 |
| 并发 | 20 job (免费) | 取决于你的机器 |
| 适用 | PR检查/冒烟测试 | 全量训练 |
| 维护 | 零维护 | 需维护CUDA/驱动 |
⚠️避坑③:Self-hosted Runner的CUDA版本和工作流里的PyTorch版本要一致。Runner服务器上
nvidia-smi显示CUDA 12.4,你pip装的PyTorch却编译自CUDA 11.8 → 大概率报CUDA error: no kernel image is available。最佳实践:锁定PyTorch版本,用Docker镜像打包整个环境,Runner只负责拉起容器。
五、模型与数据版本管理:DVC + Git LFS双剑合璧
训练流水线跑起来了,但有个灵魂拷问:三周前那个acc=0.91的模型,用的是哪个版本的训练集?
如果你的回答是"大概是当时最新pull的那版吧"——那你需要DVC + Git LFS。
5.1 Git LFS:管大文件
模型权重.pt/.bin动辄几百MB甚至几个GB,直接扔Git里仓库会炸。Git LFS(Large File Storage)把大文件替换成指针:
# 安装Git LFS git lfs install # 追踪大模型文件 git lfs track "*.pt" "*.bin" "*.pth" "*.onnx" # 追踪数据集 git lfs track "data/*.csv" "data/*.json" # 提交 .gitattributes git add .gitattributes git commit -m "chore: enable Git LFS for models and datasets" # 正常add/push,Git LFS会自动拦截大文件 git add outputs/best_model.pt git pushWorkflow中拉取LFS文件只需要加一行:
- uses: actions/checkout@v4 with: lfs: true # 自动拉取LFS文件,不用额外命令5.2 DVC:管数据版本
Git LFS解决的是"文件存哪",DVC解决的是"这个模型跟当时那版数据是什么关系"。它能精确回答:“2024-07-03 14:22这个commit的训练,用的是2024-07-01标注的那批数据,数据MD5是abc123def456。”
# 安装 pip install dvc[s3] # 初始化DVC(可选S3/GCS/Azure/SSH作为远程存储) dvc init dvc remote add -d myremote s3://my-bucket/dvc-store dvc remote modify myremote endpointurl https://s3.example.com # 追踪数据文件 dvc add data/train.csv data/val.csv data/test.csv # 追踪训练好的模型 dvc add outputs/best_model.pt dvc add outputs/model.onnx在Workflow中集成DVC:
- name: 拉取DVC数据 env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} run: | pip install dvc[s3] dvc pull # 自动拉取当前commit对应的数据版本 dvc checkout # 确保工作区文件与dvc.lock一致💡效率技巧③:DVC + Git LFS搭配使用,各管各的。LFS管模型权重和原始数据集的存储,DVC管数据版本的元信息(哪个commit对应哪批数据)。Workflow里
checkout时lfs: true拉LFS文件,然后dvc pull拉DVC追踪的数据,两者并行不冲突。
六、训练结果自动记录:MLflow无缝集成
训练完不记录,等于白训。把MLflow集成进Workflow,让每次训练自动上报到Tracking Server:
- name: 📊 MLflow训练+记录 env: MLFLOW_TRACKING_URI: ${{ secrets.MLFLOW_TRACKING_URI }} MLFLOW_EXPERIMENT_NAME: "github-actions-nlp-training" GIT_COMMIT: ${{ github.sha }} GIT_BRANCH: ${{ github.ref_name }} run: | python -c " import mlflow import torch from datetime import datetime mlflow.set_tracking_uri('${{ secrets.MLFLOW_TRACKING_URI }}') mlflow.set_experiment('${{ env.MLFLOW_EXPERIMENT_NAME }}') with mlflow.start_run(run_name=f'train-{datetime.now():%Y%m%d-%H%M}') as run: # 记录Git信息,方便追溯 mlflow.set_tag('git_commit', '${{ env.GIT_COMMIT }}') mlflow.set_tag('git_branch', '${{ env.GIT_BRANCH }}') mlflow.set_tag('trigger', '${{ github.event_name }}') mlflow.set_tag('runner', '${{ runner.name }}') # 记录超参数(从Workflow变量读取) mlflow.log_params({ 'epochs': ${{ vars.TRAIN_EPOCHS || 50 }}, 'batch_size': ${{ vars.BATCH_SIZE || 32 }}, 'learning_rate': ${{ vars.LEARNING_RATE || 0.001 }}, }) # === 实际训练逻辑 === # ... 你的训练代码 ... # 记录指标 mlflow.log_metrics({ 'val_accuracy': 0.914, 'val_loss': 0.23, 'train_time_minutes': 45.3, }) # 保存模型到MLflow mlflow.pytorch.log_model( model, 'model', registered_model_name='nlp-classifier' ) print(f'✅ MLflow Run: {run.info.run_id}') print(f'📊 Experiment: {mlflow.get_experiment(run.info.experiment_id).name}') "这样,每次git push后,MLflow侧就会多一条完整记录——包含触发来源、Git commit、超参数、指标和模型文件。你不再需要回忆"上周三下午那版用的什么参数"。
七、失败告警:训练崩了别等用户来告诉你
训练跑崩不告警,等于家里着火但烟雾报警器没装。这里给三个实用方案:
7.1 飞书机器人告警(最推荐,国内友好)
- name: 🚨 训练失败告警 if: failure() run: | curl -X POST '${{ secrets.FEISHU_WEBHOOK }}' \ -H 'Content-Type: application/json' \ -d '{ "msg_type": "interactive", "card": { "header": { "title": {"tag": "plain_text", "content": "🚨 模型训练失败"}, "template": "red" }, "elements": [ { "tag": "div", "text": { "tag": "lark_md", "content": "**仓库**: ${{ github.repository }}\n**分支**: ${{ github.ref_name }}\n**Commit**: ${{ github.sha }}\n**触发者**: ${{ github.actor }}\n**Workflow**: [查看详情](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" } } ] } }'7.2 Slack告警
- name: 训练完成通知 if: always() uses: slackapi/slack-github-action@v2 with: webhook: ${{ secrets.SLACK_WEBHOOK }} webhook-type: incoming-webhook payload: | { "text": "${{ job.status == 'success' && '✅' || '❌' }} 训练${{ job.status == 'success' && '成功' || '失败' }}\nRepo: ${{ github.repository }}\nBranch: ${{ github.ref_name }}\n<https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}|查看详情>" }7.3 钉钉告警
- name: 钉钉通知 if: failure() run: | curl -X POST '${{ secrets.DINGTALK_WEBHOOK }}' \ -H 'Content-Type: application/json' \ -d "{ \"msgtype\": \"markdown\", \"markdown\": { \"title\": \"训练失败告警\", \"text\": \"## 🚨 模型训练失败\n> 仓库: ${{ github.repository }}\n> 分支: ${{ github.ref_name }}\n> 触发者: ${{ github.actor }}\n\n[🔗 查看日志](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})\" } }"关键点:if: failure()只在上一step失败时触发;if: always()不管成功失败都触发。通常建议:失败用failure()秒级告警,成功用always()随手发个通知——省得同事以为你在摸鱼。
八、CI/CD触发训练完整流程图
把上面所有组件串起来,就是一套完整的AI训练CI/CD流水线:
flowchart TD DEV["🧑💻 开发者 git push"] -->|push to main| MAIN["🔵 main 分支"] DEV -->|open PR| PR["🟡 Pull Request"] DEV -->|tag v1.0 → release| REL["🟢 Release"] MAIN -->|触发| GH_ACTION_MAIN["GitHub Actions<br/>on: push"] PR -->|触发| GH_ACTION_PR["GitHub Actions<br/>on: pull_request"] REL -->|触发| GH_ACTION_REL["GitHub Actions<br/>on: release"] GH_ACTION_PR -->|免费CPU Runner| LINT["ruff + mypy<br/>代码检查"] LINT --> SMOKE["3-epoch冒烟测试<br/>确认loss下降"] SMOKE -->|通过 ✅| PR_MERGE["允许合并"] SMOKE -->|失败 ❌| PR_BLOCK["🚫 阻止合并<br/>+ 飞书告警"] GH_ACTION_MAIN -->|Self-hosted GPU| PULL_DATA["dvc pull<br/>拉取数据"] PULL_DATA --> LFS_PULL["git lfs pull<br/>拉取模型"] LFS_PULL --> TRAIN["python train.py<br/>完整训练"] TRAIN -->|每epoch| LOG["📊 上报MLflow<br/>loss/acc/lr"] TRAIN -->|完成| SAVE["保存checkpoint<br/>+ Git LFS push"] SAVE --> NOTIFY["✅ 飞书/Slack<br/>训练完成通知"] GH_ACTION_REL --> EXPORT["模型导出ONNX<br/>优化+量化"] EXPORT --> REGISTRY["推送到MLflow<br/>Model Registry"] REGISTRY --> PROMOTE["标记 Production<br/>触发K8s部署"] TRAIN -->|失败 ❌| ALERT_FAIL["🚨 飞书/钉钉<br/>训练失败告警<br/>含Git commit/运行URL"] style DEV fill:#9b59b6,color:#fff style TRAIN fill:#e74c3c,color:#fff style LOG fill:#4a90d9,color:#fff style NOTIFY fill:#27ae60,color:#fff style ALERT_FAIL fill:#ff6b6b,color:#fff style PR_BLOCK fill:#ff6b6b,color:#fff style PROMOTE fill:#2ecc71,color:#fff这张图就是你的AI训练自动化宪法。每次有新人问"我们训练流程是啥",直接把这张图甩过去,比讲半小时管用。
九、踩坑与技巧合集
⚠️ 避坑清单
| 坑 | 症状 | 解决方案 |
|---|---|---|
| ① timeout不设 | 训练卡死后GPU空转几小时,账单爆炸 | 设timeout-minutes: 480,取训练时间×1.5 |
| ② CUDA版本不对 | CUDA error: no kernel image available | Runner预装Docker,固定CUDA+PyTorch版本 |
| ③ artifact过期 | actions/upload-artifact默认90天过期 | 训练产物应推到MLflow/DVC/S3,artifact只做临时中转 |
| ④ 环境变量泄露 | 在日志中打印了API Key | 用${{ secrets.XXX }},不要在step里echo secrets |
| ⑤ lfs未拉取 | checkout后模型文件是个指针文本 | actions/checkout@v4加lfs: true |
💡 效率技巧
| 技巧 | 效果 |
|---|---|
| ① paths过滤 | README的commit不触发训练,省GPU |
| ② 多标签调度 | 大模型跑A100,小模型跑V100,用标签区分 |
| ③ DVC+LFS分层 | LFS存文件、DVC管版本,各司其职 |
| ④ 预装CUDA | Runner上预装CUDA+PyTorch,每次省10分钟 |
| ⑤ 矩阵策略 | strategy.matrix同时跑多组超参,GPU利用率拉满 |
十、总结与系列预告
你学完这篇文章,已经掌握了:
✅GitHub Actions触发ML训练的完整Workflow设计——push/main全量训练、PR冒烟测试、release自动部署
✅GPU Runner的配置与调度——GitHub-hosted免费跑检查,Self-hosted GPU正经跑训练
✅DVC + Git LFS的模型数据版本管理——不再迷失在"final_v3_final_real.pt"的迷宫里
✅MLflow无缝集成——每次训练自动记录参数、指标、模型,可追溯、可复现
✅失败告警策略——飞书/钉钉/Slack,训练崩了第一时间知道
但更重要的是——你从此不用再手动SSH上GPU、手动配环境、手动记录结果了。git push然后去喝杯咖啡,回来训练结果已经在MLflow里等着你了。这才叫自动化。
文末三件套
📋 自查清单
- [ ] 你的
.github/workflows/train.yml里设了timeout-minutes吗? - [ ] GPU Runner的CUDA版本和PyTorch版本一致吗?
- [ ]
actions/checkout带了lfs: true吗? - [ ] 训练失败后有告警通知吗(飞书/钉钉/Slack)?
- [ ] 训练结果自动记录到MLflow了吗?
- [ ] 关键文件路径加到了
paths过滤了吗? - [ ] Secrets(MLFLOW_TRACKING_URI等)配置了吗?
🔗 推荐扩展阅读
- GitHub Actions 官方文档 —— YAML语法、Context、表达式
- MLflow Tracking 文档 —— 实验追踪的完整API
- DVC + Git LFS 最佳实践 —— 数据版本管理进阶
- Self-hosted Runner 部署指南 —— GPU Runner配置详解
📢 系列预告
下一篇:《L5实战——AI DevOps平台搭建(三):Kubernetes模型服务部署》
你将学到:K8s上部署模型服务的完整方案,包括HPA自动扩缩容、滚动更新零停机、GPU节点调度、Ingress流量分发,以及Prometheus + Grafana生产级监控面板。
模型训好了,接下来该让它真正干活了。我们下一篇见 🔥
标签:GitHub Actions、MLOps、模型训练、CI/CD、Git LFS、MLflow、自动化流水线