📑 本页目录(点开跳转)
23 · 可观测性与成本
⏱ 26 分钟 | ⭐ 让优化变成一件可管理的事
🎯 一句话
你无法优化你没有测量的东西。 这一章把前面 22 章的所有指标收拢成一套可以长期运行的观测体系 —— 以及一份"钱到底花在哪"的账。
📊 一、四层指标体系
- 用户感知延迟 P95/P99
- KV Cache 使用率 ⭐⭐、抢占次数
- 通信/计算重叠率、数据管线吞吐
- NVLink/网络流量、温度、功耗、ECC 计数
🔑 诊断的正确方向是【从上往下】: 先看业务指标异常,再逐层下钻找原因。 反过来(盯着 GPU 利用率优化)会让你优化一堆不影响业务的东西。
🎯 二、每一层最该盯的那一个
| 层 | 最该盯的指标 | 为什么 |
|---|---|---|
| 业务 | 每百万 token 成本 | 唯一能和钱直接对应的数字 |
| 服务 | KV Cache 使用率 ⭐ | 比 GPU 利用率更早的容量预警(第 20 章) |
| 框架 | MFU ⭐ | 唯一能回答"还剩多少空间"(第 4 章) |
| 硬件 | 带宽利用率 ⭐ | 大部分负载是带宽瓶颈(第 3 章) |
⚠️
nvidia-smi的 GPU-Util 不在这个列表里 —— 第 2 章说过, 它只表示"有 kernel 在跑",一个只用 5% 算力的 kernel 也显示 100%。 它几乎没有诊断价值。
# ⭐ 训练时该记的最小指标集
import torch
metrics = {
"loss": loss.item(),
"grad_norm": gn.item(),
"lr": sched.get_last_lr()[0],
"mfu": compute_mfu(tokens_per_sec), # 第 4 章
"step_time_ms": dt * 1000,
"data_wait_ms": data_wait * 1000, # ⭐ 数据等待时间
"mem_alloc_gb": torch.cuda.max_memory_allocated() / 1e9,
"mem_reserved_gb": torch.cuda.max_memory_reserved() / 1e9, # ⭐ 差值=碎片
"tokens_seen": total_tokens,
}
💰 三、成本模型:钱花在哪
训练总成本 = GPU 小时数 × 单价
= (6 × N × D) / (卡数 × 峰值FLOPS × MFU) / 3600 × 卡数 × 单价
⭐ 简化后:训练成本 ∝ 1 / MFU
→ MFU 从 25% 提到 50%,成本【直接减半】
def training_cost(params_B, tokens_T, n_gpus, mfu,
peak_tflops=312, hourly=2.0):
flops = 6 * params_B * 1e9 * tokens_T * 1e12
seconds = flops / (n_gpus * peak_tflops * 1e12 * mfu)
return seconds / 3600 * n_gpus * hourly, seconds / 86400
cost, days = training_cost(7, 1.0, 64, 0.45)
print(f"MFU 45%: ${cost:,.0f},{days:.0f} 天") # $6,912,54 天
cost, days = training_cost(7, 1.0, 64, 0.25)
print(f"MFU 25%: ${cost:,.0f},{days:.0f} 天") # $12,442,97 天 ⭐ 多花 80%
推理成本的三个杠杆
每百万 token 成本 = GPU 时价 ÷ (吞吐 × 3600 × 利用率) × 1e6
⭐ 三个杠杆,收益依次递减:
① 提高吞吐 (量化、连续批处理、更好的引擎)→ 常有 5-10 倍空间
② 提高平均利用率 (把离线任务填到低峰期) → 常有 2 倍空间 ⭐
③ 换更便宜的卡 (量化后可能装得下) → 1.5-3 倍
⭐ 第 ② 条最容易被忽略: 很多服务的日间峰值和夜间低谷差 5 倍以上, 但集群是按峰值买的。把批量推理、评测、数据处理这类可延迟的任务 调度到低峰期,等于免费拿到大量算力。
🔬 四、profiling 工具链
| 工具 | 用途 |
|---|---|
| PyTorch Profiler ⭐ | 最常用,能看 kernel 时间线和显存(第 4 章) |
| Nsight Systems | 系统级时间线,看通信/计算重叠最好用 ⭐ |
| Nsight Compute | 单个 kernel 的深度分析(算术强度、occupancy) |
| DCGM | 集群级 GPU 监控,Prometheus 集成 |
torch.cuda.memory_viz |
显存快照可视化(第 9 章) |
# ⭐ Nsight Systems:看多卡的通信和计算是否重叠
nsys profile -t cuda,nvtx,nccl -o report python train.py
# 给代码段打标记,在时间线上能看到
import torch.cuda.nvtx as nvtx
with nvtx.range("forward"): out = model(x)
with nvtx.range("backward"): loss.backward()
with nvtx.range("optimizer"): opt.step()
# ⭐ 这样在 Nsight 时间线上能一眼看出各阶段占比
💡 什么时候用 Nsight 而不是 PyTorch Profiler: 当你怀疑通信没有和计算重叠时。 PyTorch Profiler 能看到 nccl kernel 的耗时, 但 Nsight Systems 能直观看到它们在时间线上是并排还是串行的。
🧭 五、一套可复用的优化流程
① 建立基线
· 记录当前 MFU / 吞吐 / 成本
· ⭐ 没有基线就没有"改进",只有"感觉变快了"
② 定位瓶颈(按顺序排除)
· 数据管线? → 换随机张量测(第 22 章)
· 通信? → 单卡 vs 多卡对比
· 显存/碎片? → memory snapshot
· 算子? → profiler 看 top kernel
· 算力/带宽? → 算算术强度(第 3 章)
③ 只改一件事,然后测
· ⭐ 同时改两个,你不知道是哪个起作用
· 也不知道它们有没有互相抵消
④ 记录到实验表
· 改动、MFU、吞吐、成本、结论
⑤ 回到 ②
🔑 这个流程和 Kaggle 方法论、 ML 基础的调试手册是同构的: 建立基线 → 定位瓶颈 → 单变量实验 → 记录。 领域不同,方法论一样。
📋 六、一张诊断速查表
| 症状 | 最可能的原因 | 去哪一章 |
|---|---|---|
| MFU < 20% | 数据管线没喂饱 | 22 |
| 单卡快、多卡慢 | 通信瓶颈 / 拓扑不对 | 05、14 |
| OOM 但 batch=1 也 OOM | 优化器状态 | 09、11 |
| 显存够却报 OOM | 碎片 | 09 |
| 开了 AMP 没变快 | 维度没对齐 / 模型太小 | 06 |
torch.compile 没提速 |
graph break | 07 |
| 推理吞吐低 | KV Cache 碎片 / 没用连续批处理 | 16、17 |
| 解码速度慢 | 带宽瓶颈,考虑量化 | 15、18 |
| TPOT 有毛刺 | 长 prefill 插队 | 17 |
| 训练卡死无报错 | AllReduce 挂死 | 10、21 |
| loss 突然尖峰 | 异常数据 / FP16 溢出 | 21、06 |
🔗 和站内其他章的关系
| 相关的地方 | 这里的位置 |
|---|---|
| 第 4 章 MFU | 框架层的核心指标 |
| 第 20 章 KV Cache 使用率 | 服务层的核心指标 |
| 第 1 章 先测再优化 | 本章是那句话的完整流程 ⭐ |
| ML 基础第 11 章 | 同构的方法论 |
✅ 检查点
- 四层指标体系是什么?诊断该从哪一层开始?
- 每一层最该盯的指标各是什么?
- 为什么
nvidia-smi的 GPU-Util 不在名单里? - 训练成本和 MFU 是什么关系?MFU 从 25% 到 50% 省多少?
- 推理降成本的三个杠杆?哪个最容易被忽略?
- 什么时候该用 Nsight Systems 而不是 PyTorch Profiler?
- 优化流程的五步是什么?为什么"只改一件事"?
- "MFU < 20%" 最可能是什么原因?
👀 答案
- 业务层 / 服务层 / 框架层 / 硬件层。诊断应该从上往下——先看业务指标异常再逐层下钻。反过来盯着 GPU 利用率优化会优化一堆不影响业务的东西。
- 业务层:每百万 token 成本;服务层:KV Cache 使用率;框架层:MFU;硬件层:带宽利用率。
- 因为它只表示"有 kernel 在跑",一个只用 5% 算力的 kernel 也显示 100%——几乎没有诊断价值。
- 训练成本 ∝ 1/MFU。MFU 从 25% 提到 50%,成本直接减半(例子里从 $12,442/97 天降到 $6,912/54 天)。
- ①提高吞吐(5-10 倍空间)②提高平均利用率(2 倍空间)③换更便宜的卡。第 ② 条最容易被忽略——日夜峰谷差 5 倍以上但集群按峰值买,把可延迟的批量任务调度到低峰期等于免费拿算力。
- 当你怀疑通信没有和计算重叠时。PyTorch Profiler 能看到 nccl kernel 耗时,但 Nsight Systems 能直观看到它们在时间线上是并排还是串行。
- ①建立基线 ②定位瓶颈 ③只改一件事然后测 ④记录到实验表 ⑤回到②。只改一件事是因为同时改两个你不知道是哪个起作用,也不知道它们有没有互相抵消。
- 数据管线没喂饱(第 22 章)。
🛑 可以停在这里
⚡ 走神救援
⭐你无法优化你没有测量的东西。四层指标:业务(每百万 token 成本)/ 服务(⭐⭐KV Cache 使用率,比 GPU 利用率更早的容量预警)/ 框架(⭐MFU,唯一能回答"还剩多少空间")/ 硬件(⭐带宽利用率);⭐诊断要从上往下——反过来盯 GPU 利用率会优化一堆不影响业务的东西。⚠️
nvidia-smi的 GPU-Util 不在名单里(只表示"有 kernel 在跑",5% 算力也显示 100%,几乎没有诊断价值)。⭐⭐训练成本 ∝ 1/MFU——MFU 从 25% 提到 50% 成本直接减半($12,442/97天 → $6,912/54天)。推理降成本三杠杆:提吞吐(5-10 倍空间)、⭐提平均利用率(2 倍空间,最容易被忽略——日夜峰谷差 5 倍但集群按峰值买,把可延迟的批量任务填到低峰期等于免费拿算力)、换便宜的卡。工具:PyTorch Profiler 最常用,⭐怀疑通信没和计算重叠时用 Nsight Systems(能直观看到时间线上是并排还是串行),配nvtx.range打标记。⭐优化流程五步:①建立基线(没有基线就只有"感觉变快了")②按序定位瓶颈(数据管线→通信→显存→算子→算力/带宽)③⭐只改一件事再测(同时改两个不知道是哪个起作用,也不知道有没有互相抵消)④记录 ⑤回到②——和 Kaggle 方法论、ML 调试手册同构。记住那张诊断速查表:MFU<20% 查数据管线、单卡快多卡慢查通信、显存够却 OOM 是碎片、AMP 没提速查维度对齐、compile 没提速查 graph break、训练卡死无报错是 AllReduce 挂死。
下一节 👉 24-实战与挑战项目.md ⭐