1. 为什么 `nvidia-smi` 会骗人?
打开训练任务,看到 GPU Utilization 一直稳定在 95% 以上,很多人会认为 GPU 已经被“打满”。但这里有一个关键问题:
GPU Utilization 只说明 GPU 上有 warp 在执行,不区分是在做矩阵乘、搬运内存,还是在空转。
实际情况可能是:内存带宽已经饱和,算力只跑了一半;或者通信 overhead 让核心大部分时间都在等数据。我们需要一个指标,衡量的是“真正用于模型计算”的算力比例。
2. MFU 的定义
MFU(Model FLOPs Utilization)最早由 Google PaLM 团队提出,定义非常直接:
MFU = (模型每秒所需 FLOPs) ÷ (GPU 理论峰值 FLOPs/s)
分子是“模型完成一次前向+反向真正需要的浮点运算量”,分母是硬件在对应精度下能提供的最大浮点运算量。MFU 高,说明 GPU 把大部分时间花在了有用的矩阵计算上。
3. LLM 的 FLOPs 怎么算?
对于 dense Transformer,PaLM 论文给出每 token 的理论 FLOPs:
FLOPs/token = 6N + 12 · l · h · q · t
其中 N 是非 embedding 参数量,l 是层数,h 是注意力头数,q 是每头维度,t 是序列长度。
为什么是 6N?
训练时每个参数大约参与 6 次浮点运算:
- 前向传播:2 FLOPs(乘 + 加)
- 反向传播激活梯度:2 FLOPs
- 反向传播权重梯度:2 FLOPs
所以总计算量与参数量的关系是近似线性的 6N。attention 部分则额外与序列长度 t 相关,大模型上下文一长,attention 的 12lhqt 项会显著增长。
Causal mask 要砍半
自回归 LLM 使用 causal mask,每个 token 只能看到自己和之前的 token。完整的 attention 矩阵有一半不需要计算,因此 attention 项通常要除以 2:
FLOPs/token ≈ 6N + 6 · l · h · q · t
如果不砍半,MFU 可能算出大于 100% 的荒谬结果。
4. CNN、ViT、LLM 的计算差异
三种架构的 FLOPs 由不同的“增长引擎”驱动:
- 传统 CNN:受输入分辨率、通道数和 kernel 大小驱动。卷积核在 spatial 上参数共享,公式核心是 2HWC_inK²C_out。
- ViT:把图像切成 patch 后当成 token,使用全局 self-attention。FLOPs 随 patch 数量二次增长,attention 项是 2ln²d 量级。
- LLM:同样基于 Transformer,但序列很长、参数极大,总 FLOPs 近似 6N 加上与 t 相关的 attention 项。
一句话总结:CNN 的增长看“图有多大、核有多宽”;ViT 和 LLM 的增长看“token 有多少、序列有多长”。
5. 开源工具怎么选?
手算公式适合理解和快速估算,实际工程中常用工具辅助:
- calflops:推荐用于快速估算,严格区分 FLOPs 和 MACs,支持 HuggingFace 模型和 tokenizer。
- DeepSpeed Flops Profiler:适合训练阶段的全流程 profiling,能看到模块级前向/反向耗时。
- fvcore / ptflops:CV 模型常用,但要注意它们输出的往往是 MACs 而非真正的 FLOPs。
6. 本课推荐延伸阅读
首要来源:PaLM: Scaling Language Modeling with Pathways,重点读 Appendix B 的 FLOPs 推导和 MFU 定义。
7. 接下来可以问的问题
如果以下内容还有不清楚的地方,随时问我:
- 能否给我自己模型的配置算一个具体的 MFU?
- MFU 和 HFU 到底怎么区分?activation checkpointing 的影响怎么算?
- 推理阶段(prefill + decode)的 MFU 计算和训练有什么不同?
- 想针对 CNN / ViT 做更详细的 FLOPs 拆解,该怎么展开?