训练工程——千卡集群的管理与故障恢复 / Training Engineering for Thousand-GPU Cluster Operations and Recovery
📅 创建时间:2026-06-02 🏷️ 标签:#Checkpoint #容错 #实验追踪 #WandB #GPU调度 #故障恢复 #弹性训练 📚 前置知识:[[02-distributed-training]](分布式训练) [[05-pretraining]](预训练) 📚 相关知识:[[03-memory-optimization]](显存优化) [[09-training-engineering]]
场景:10000 张卡跑 30 天,第 15 天一张卡坏了怎么办
┌─────────────────────────────────────────────────────────────┐
│ │
│ 你的训练任务: │
│ • 10000 张 H100,跑 30 天 │
│ • 总 GPU 小时:10000 × 24 × 30 = 7,200,000 小时 │
│ • 单 GPU 成本:$2-3/小时(云端) │
│ • 总成本:约 $15,000,000 - $21,000,000 │
│ │
│ 问题来了: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ MTBF(平均故障间隔时间): │ │
│ │ 单张 H100 的 MTBF ≈ 10,000 小时 │ │
│ │ │ │
│ │ 10000 张卡同时运行: │ │
│ │ → 平均每 1 小时就有 1 张卡可能故障 │ │
│ │ → 30 天训练期间,几乎必然发生多次故障 │ │
│ │ │ │
│ │ 如果没有故障恢复机制: │ │
│ │ → 一张卡坏了,整个训练停止 │ │
│ │ → 30 天训练前功尽弃 │ │
│ │ → 浪费 $7,000,000+ 的计算资源 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 训练工程要解决的核心问题: │
│ → 如何让 10000 张卡稳定运行 30 天? │
│ → 如何在故障后快速恢复? │
│ → 如何管理数百个并行实验? │
│ │
└─────────────────────────────────────────────────────────────┘第1节:Checkpoint 管理——保存什么、何时保存、存哪里
Checkpoint 的内容构成
┌─────────────────────────────────────────────────────────────┐
│ Checkpoint 包含的内容 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 完整 Checkpoint 的构成: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ checkpoint_step_10000/ │ │
│ │ ├── model.safetensors # 模型权重(必须) │ │
│ │ │ ( safetensors 格式更安全)│ │
│ │ ├── model.safetensors.index.json # 分布式权重索引│ │
│ │ ├── optimizer.safetensors # 优化器状态(可选) │ │
│ │ ├── scheduler.pt # 学习率调度器状态 │ │
│ │ ├── rng_state.pth # 随机数状态(必须) │ │
│ │ ├── train_state.json # 训练元信息 │ │
│ │ └── zero_pp_rank_0/ # ZeRO/PP 分片信息 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 各项的必要性: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 权重(必须):恢复模型参数 │ │
│ │ 优化器状态(强烈推荐): │ │
│ │ → 没有优化器状态 → 从头计算优化器 │ │
│ │ → 浪费大量计算,但不致命 │ │
│ │ 随机数状态(必须): │ │
│ │ → 没有 → 数据顺序不同步,重复训练某些数据 │ │
│ │ 学习率调度器(可选): │ │
│ │ → 可以从 step 推断 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Checkpoint 保存策略
┌─────────────────────────────────────────────────────────────┐
│ Checkpoint 保存策略:频率与优化 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 策略 1:固定步数间隔(简单,但可能浪费) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ save_steps = [1000, 2000, 3000, 4000, ...] │ │
│ │ → 每 1000 步保存一个 │ │
│ │ → 简单实现 │ │
│ │ → 但训练初期 checkpoint 频繁,中后期浪费 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 策略 2:指数增长间隔(推荐) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ save_steps = [100, 200, 400, 800, 1600, ...] │ │
│ │ │ │
│ │ 思路: │ │
│ │ → 训练初期参数不稳定,需要频繁恢复点 │ │
│ │ → 训练后期参数稳定,少量恢复点足够 │ │
│ │ → 节省存储 + 保存时间 │ │
│ │ │ │
│ │ 缺点:无法指定具体步数(如"回到第 3000 步") │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 策略 3:基于时间间隔(适合长时间训练) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ save_interval_minutes = 30 │ │
│ │ → 每 30 分钟保存一个(与步数无关) │ │
│ │ → 确保故障损失不超过 30 分钟的训练 │ │
│ │ → 存储成本可控(总 checkpoint 数 ≈ 训练时长/30) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 混合策略(最佳): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • 每 1000 步保存(正常检查点) │ │
│ │ • 每 30 分钟保存(容错检查点) │ │
│ │ • 保留最近 N 个(如 5 个),删除旧的 │ │
│ │ → 平衡存储成本和恢复灵活性 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘Checkpoint 存储格式优化
┌─────────────────────────────────────────────────────────────┐
│ Checkpoint 存储格式:速度 vs 存储成本 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 70B 模型 Checkpoint 大小: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 格式 │ 大小 │ 保存速度 │ │
│ │ ───────────────────┼──────────────┼───────────────────│ │
│ │ FP32 全量 │ ~1.1 TB │ 慢(高压缩率) │ │
│ │ BF16 全量 │ ~560 GB │ 中等 │ │
│ │ BF16(只权重) │ ~140 GB │ 快 │ │
│ │ safetensors │ ~140 GB │ 快 + 安全 │ │
│ │ 分片保存(ZeRO-3)│ ~18 GB/卡 │ 快(并行) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 推荐方案: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. 保存格式:BF16 + safetensors │ │
│ │ → 速度快(内存映射,无需加载到 RAM) │ │
│ │ → 安全(防序列化漏洞) │ │
│ │ │ │
│ │ 2. 优化器状态:可以只保存最新 1-2 个 │ │
│ │ → 节省大量存储(优化器状态占大头) │ │
│ │ │ │
│ │ 3. 存储位置: │ │
│ │ → 热数据(最近):NVMe SSD(快速) │ │
│ │ → 冷数据(历史):对象存储 COS/S3(便宜) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第2节:故障检测与自动恢复
常见的训练故障类型
┌─────────────────────────────────────────────────────────────┐
│ 训练故障分类与诊断 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 硬件故障(最常见): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. GPU ECC Error │ │
│ │ → GPU 显存出现错误,被 ECC 纠正或无法纠正 │ │
│ │ → 症状:CUDA 错误,Xid 49/74 │ │
│ │ → 解决:重启该 GPU,重新加载 checkpoint │ │
│ │ │ │
│ │ 2. NCCL Timeout │ │
│ │ → 某张卡通信超时(通常 30-60 分钟无响应) │ │
│ │ → 症状:NCCL timeout,rank N lost │ │
│ │ → 原因:GPU 卡死、网络抖动、NVLink 断开 │ │
│ │ → 解决:重置集群,从 checkpoint 恢复 │ │
│ │ │ │
│ │ 3. NVLink/IB 链路故障 │ │
│ │ → 节点间通信中断 │ │
│ │ → 症状:通信异常,某几个 rank 无法同步 │ │
│ │ → 解决:切换到备用节点,或降级到以太网 │ │
│ │ │ │
│ │ 4. NVMe/存储写入失败 │ │
│ │ → Checkpoint 保存失败 │ │
│ │ → 症状:IOError,磁盘满 │ │
│ │ → 解决:清理旧 checkpoint,扩展存储 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 软件故障: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 5. Python OOM │ │
│ │ → 进程内存耗尽 │ │
│ │ → 症状:SIGKILL,OOM Killer │ │
│ │ → 解决:减小 batch size,检查内存泄漏 │ │
│ │ │ │
│ │ 6. CUDA OOM(显存耗尽) │ │
│ │ → 显存分配失败 │ │
│ │ → 症状:CUDA out of memory │ │
│ │ → 解决:减小模型/序列长度,增加梯度累积 │ │
│ │ │ │
│ │ 7. PyTorch 内部错误 │ │
│ │ → 如 illegal memory access │ │
│ │ → 症状:RuntimeError │ │
│ │ → 解决:检查索引越界、类型不匹配等 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘故障检测机制
┌─────────────────────────────────────────────────────────────┐
│ 故障检测与监控指标 │
├─────────────────────────────────────────────────────────────┤
│ │
│ GPU 层面监控: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 1. nvidia-smi 指标 │ │
│ │ → GPU 利用率(< 50% = 异常) │ │
│ │ → 显存使用(接近 100% = 可能 OOM) │ │
│ │ → 温度(> 85°C = 过热降频) │ │
│ │ → ECC 错误计数(> 0 = 硬件问题) │ │
│ │ │ │
│ │ 2. Xid 错误日志 │ │
│ │ dmesg | grep Xid │ │
│ │ → Xid 49:GPU ECC 错误 │ │
│ │ → Xid 79:GPU 崩溃 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 训练层面监控: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 3. Loss 异常检测 │ │
│ │ → Loss > 阈值(如 100)= Spike │ │
│ │ → Loss = nan = 数值溢出 │ │
│ │ → Loss 不再下降 = 可能收敛完成或退化 │ │
│ │ │ │
│ │ 4. 梯度异常检测 │ │
│ │ → grad_norm > 阈值 = 梯度爆炸 │ │
│ │ → grad_norm = 0 = 梯度消失 │ │
│ │ │ │
│ │ 5. 吞吐量异常检测 │ │
│ │ → samples/sec 突然下降 = GPU 卡顿 │ │
│ │ → 长时间无日志输出 = 进程挂起 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 分布式层面监控: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 6. NCCL 通信健康 │ │
│ │ → AllReduce 平均时间 > 阈值 │ │
│ │ → 某个 rank 响应慢 │ │
│ │ → NCCL timeouts │ │
│ │ │ │
│ │ 7. DataLoader 健康 │ │
│ │ → prefetch buffer 空 = 数据加载卡住 │ │
│ │ → 多 worker GPU 利用率不一致 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘自动恢复流程
┌─────────────────────────────────────────────────────────────┐
│ 自动故障恢复流程 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 1:检测故障(健康检查循环) │ │
│ │ │ │
│ │ while training: │ │
│ │ if detect_anomaly(): │ │
│ │ trigger_recovery() │ │
│ │ │ │
│ │ 检测触发条件: │ │
│ │ → NCCL Timeout(通常 30 分钟无响应) │ │
│ │ → GPU 利用率 = 0 超过 N 分钟 │ │
│ │ → Loss = nan │ │
│ │ → 进程退出码非 0 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 2:保存当前 progress(尽量不丢失) │ │
│ │ │ │
│ │ try: │ │
│ │ save_checkpoint("emergency") │ │
│ │ except: │ │
│ │ pass # 最坏情况:丢弃当前步 │ │
│ │ │ │
│ │ 同时记录: │ │
│ │ → 当前 step 数 │ │
│ │ → 当前数据 shard │ │
│ │ → 异常原因 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 3:终止所有进程,清理资源 │ │
│ │ │ │
│ │ for rank in all_ranks: │ │
│ │ kill_process(pid[rank]) │ │
│ │ cleanup_tmp_files() │ │
│ │ │ │
│ │ ⚠️ 必须确保所有 rank 同时终止 │ │
│ │ ⚠️ 防止僵尸进程占用 GPU 显存 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 4:请求新 GPU 资源 │ │
│ │ │ │
│ │ 与集群调度器交互: │ │
│ │ → Kubernetes / Slurm / Ray 释放坏节点 │ │
│ │ → 申请新节点 │ │
│ │ → 等待资源分配 │ │
│ │ │ │
│ │ 时间:通常 2-10 分钟 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Step 5:重新启动训练 │ │
│ │ │ │
│ │ 1. 加载最新 checkpoint │ │
│ │ 2. 重新初始化 NCCL 通信 │ │
│ │ 3. 恢复数据加载器(精确位置) │ │
│ │ 4. 继续训练 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘弹性训练——支持节点动态加入退出
┌─────────────────────────────────────────────────────────────┐
│ 弹性训练:动态扩缩容 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 理想情况:训练集群支持节点动态增减 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 场景:跑满 10000 张卡时,某节点故障 │ │
│ │ │ │
│ │ 选项 A(停机恢复): │ │
│ │ → 等待新节点分配,停机 10 分钟 │ │
│ │ → 从 checkpoint 恢复 │ │
│ │ → 效率损失:~0.1%(可接受) │ │
│ │ │ │
│ │ 选项 B(弹性训练): │ │
│ │ → 暂时用 9992 张卡继续跑 │ │
│ │ → 新节点加入时自动注册 │ │
│ │ → 梯度分片重新分配 │ │
│ │ → 无需停机 │ │
│ │ │ │
│ │ 挑战: │ │
│ │ → 分布式训练的 rank 不能动态增减(需要重新初始化)│ │
│ │ → 需要框架支持 elastic / fault-tolerant 训练 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 工业实践(Horovod / Ray Train / DeepSpeed): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ DeepSpeed Elastic Training: │ │
│ │ → 支持训练中动态调整 world size │ │
│ │ → 发现慢节点时自动跳过或重新分配 │ │
│ │ → 但实际生产中,大多数公司仍用停机恢复 │ │
│ │ │ │
│ │ 原因:弹性训练需要框架支持,工程复杂度高 │ │
│ │ → 停机 10 分钟 vs 停机 30 分钟,前者可接受 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第3节:实验追踪与管理
实验追踪的核心指标
┌─────────────────────────────────────────────────────────────┐
│ 实验追踪:记录什么 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 训练 metrics(必须记录): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • step, epoch │ │
│ │ • train_loss, val_loss │ │
│ │ • learning_rate │ │
│ │ • grad_norm │ │
│ │ • throughput(samples/sec, tokens/sec) │ │
│ │ • gpu_utilization │ │
│ │ • gpu_memory_used │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. 配置参数(必须记录): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • model: Llama-3-8B │ │
│ │ • learning_rate: 1e-4 │ │
│ │ • batch_size: 16 │ │
│ │ • seq_length: 4096 │ │
│ │ • warmup_steps: 2000 │ │
│ │ • total_steps: 100000 │ │
│ │ • data_mix: ["web", "code", "book"] │ │
│ │ • seed: 42 │ │
│ │ • deepspeed_config: {...} │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. 评估指标(周期性记录): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • MMLU accuracy │ │
│ │ • GSM8K accuracy │ │
│ │ • HumanEval pass@1 │ │
│ │ • 各种自定义评估集 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 4. 训练元信息: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ • experiment_name: "llama3-8b-sft-v3" │ │
│ │ • run_id: "abc123" │ │
│ │ • started_at, finished_at │ │
│ │ • git_commit, git_diff │ │
│ │ • checkpoint_path │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘WandB / MLflow 使用实践
python
# WandB 集成示例
import wandb
# 初始化
wandb.init(
project="llama3-sft",
name="run-2024-01-15-lr1e-4",
config={
"model": "Llama-3-8B",
"learning_rate": 1e-4,
"batch_size": 16,
"epochs": 3,
},
tags=["sft", "baseline", "v3"],
notes="这是新的数据配比实验",
)
# 训练循环
for step, batch in enumerate(dataloader):
loss = train_step(batch)
# 记录训练 metrics
wandb.log({
"step": step,
"train_loss": loss,
"learning_rate": scheduler.get_last_lr()[0],
"grad_norm": grad_norm,
"throughput": samples_per_sec,
}, step=step)
# 周期性评估
if step % 1000 == 0:
eval_metrics = evaluate(model, eval_loader)
wandb.log({"eval_loss": eval_metrics["loss"]}, step=step)
# 记录样本级别的预测
wandb.log({
"sample_predictions": wandb.Table(
columns=["input", "target", "predicted"],
data=[
["Hello", "World", "World"],
["How are you", "Fine", "Good"],
]
)
}, step=step)
# 结束
wandb.finish()实验管理最佳实践
┌─────────────────────────────────────────────────────────────┐
│ 实验管理:如何组织数百个实验 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 目录结构: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ experiments/ │ │
│ │ ├── llama3-8b-sft/ │ │
│ │ │ ├── run-001-lr1e-4/ │ │
│ │ │ │ ├── config.yaml │ │
│ │ │ │ ├── checkpoints/ │ │
│ │ │ │ └── logs/ │ │
│ │ │ ├── run-002-lr5e-5/ │ │
│ │ │ └── run-003-lora-r8/ │ │
│ │ └── llama3-70b-pretrain/ │ │
│ │ └── run-001/ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 命名规范(推荐): │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ {model}-{task}-{date}-{variant} │ │
│ │ │ │
│ │ 例如: │ │
│ │ → llama3-8b-sft-20240115-lr1e4 │ │
│ │ → llama3-8b-sft-20240115-lora-r16 │ │
│ │ → llama3-70b-pt-20240120-baseline │ │
│ │ │ │
│ │ variant 命名规范: │ │
│ │ → lr{X}:学习率 │ │
│ │ → bs{X}:batch size │ │
│ │ → lora-r{X}:LoRA rank │ │
│ │ → seq{X}:序列长度 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 消融实验(Ablation Study)管理: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 实验组命名:ablation-{component}-{baseline-vs-variant} │ │
│ │ │ │
│ │ 例如: │ │
│ │ → ablation-data-ratio-70-30-vs-80-20 │ │
│ │ → ablation-warmup-1k-vs-2k │ │
│ │ → ablation-target-modules-qkv-vs-qkvo │ │
│ │ │ │
│ │ 消融实验的核心: │ │
│ │ → 每次只改变一个变量 │ │
│ │ → 其他配置完全相同 │ │
│ │ → 准确归因到变化的原因 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘第4节:超参搜索与调度
分布式超参搜索
┌─────────────────────────────────────────────────────────────┐
│ 分布式超参搜索策略 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 策略 1:Grid Search(穷举) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ lr: [1e-5, 5e-5, 1e-4, 5e-4] │ │
│ │ batch_size: [8, 16, 32] │ │
│ │ → 总计:4 × 3 = 12 个实验 │ │
│ │ │ │
│ │ 适用:参数空间小(≤ 3 个维度,每个 3-5 个值) │ │
│ │ 缺点:组合爆炸,不适合连续参数 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 策略 2:Random Search(随机) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 随机采样 N 个配置 │ │
│ │ → 通常比 Grid Search 更高效 │ │
│ │ → 适合高维参数空间 │ │
│ │ │ │
│ │ 理论支持: │ │
│ │ → 如果 top-10% 的配置均匀分布在参数空间 │ │
│ │ → Random Search 更容易命中 │ │
│ │ → Grid Search 容易在不重要维度浪费 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 策略 3:Bayesian Optimization(贝叶斯优化) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 思路: │ │
│ │ → 基于已有实验结果,建模参数 → 性能的映射 │ │
│ │ → 选择下一个配置时,最大化"期望提升" │ │
│ │ → 比 Random Search 更高效 │ │
│ │ │ │
│ │ 工具: │ │
│ │ → Optuna(推荐,开源) │ │
│ │ → Ray Tune │ │
│ │ → Weights & Biases Sweeps │ │
│ │ │ │
│ │ 适用:评估成本高(每个实验需要数小时) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 策略 4:Population-Based Training(PBT) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 思路: │ │
│ │ → 并行训练 N 个不同配置的模型 │ │
│ │ → 每隔一定步数,比较性能 │ │
│ │ → 差的模型"借鉴"好模型的超参 │ │
│ │ → 类似于遗传算法 + 实时超参调整 │ │
│ │ │ │
│ │ 优势: │ │
│ │ → 同时探索和利用 │ │
│ │ → 不需要预先定义搜索空间 │ │
│ │ │ │
│ │ 适用:大规模预训练(DeepMind 用这个训练 AlphaStar)│ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘升华:训练工程的工程哲学
┌─────────────────────────────────────────────────────────────┐
│ 训练工程的核心工程哲学 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 故障是必然,Recovery 是必须 │
│ → 10000 张卡跑 30 天,故障概率 ≈ 100% │
│ → 不要假设"不会坏",要假设"随时可能坏" │
│ → Checkpoint 是保险,不是浪费 │
│ │
│ 2. 测量是一切优化的起点 │
│ → 不要猜测瓶颈在哪里,用 profiler 看 │
│ → GPU 利用率、Loss 曲线、吞吐量都是信号 │
│ → 盲目优化是浪费时间 │
│ │
│ 3. 实验管理的价值在于可复现性 │
│ → 今天的结果,三个月后要能复现 │
│ → 配置、代码、数据版本必须精确记录 │
│ → WandB/MLflow 是工具,良好的习惯才是核心 │
│ │
│ 4. 自动化减少人工干预 │
│ → 故障自动检测、自动恢复 │
│ → 实验自动调度、自动评估 │
│ → 人工介入越少,出错概率越低 │
│ │
│ 一句话总结: │
│ 训练工程把"能跑"变成"跑得稳、跑得快、跑得明白"。 │
│ 细节决定成败,工程保障一切。 │
│ │
└─────────────────────────────────────────────────────────────┘"AI 可查 vs 必须理解"清单
AI 可查:
✅ WandB / MLflow 的具体 API 文档
✅ Kubernetes / Slurm 的 GPU 调度配置
✅ Optuna / Ray Tune 的超参搜索配置
必须理解:
🔴 Checkpoint 的必要内容:权重 + 随机数状态(优化器状态可选)
🔴 Checkpoint 保存频率策略:指数增长 vs 固定间隔 vs 基于时间
🔴 常见训练故障类型:GPU ECC / NCCL Timeout / CUDA OOM / Xid 错误
🔴 自动恢复流程:检测 → 保存 progress → 终止进程 → 申请资源 → 重启
🔴 为什么 checkpoint 保存时需要 NCCL barrier(确保所有 rank 同步)
🔴 实验追踪必须记录的内容:metrics + config + 评估结果 + git commit
🔴 消融实验的设计原则:每次只改变一个变量,其他完全相同学习状态:🟡 开始学习