性能优化:fused kernel / chunked communication / grad ckpt
跑通了不代表跑得快。本章把 ColossalAI 里影响吞吐的 8 个核心开关讲清楚, 让你能按需选用、知道每一项的代价。
10.1性能基线:MFU 怎么算
MFU(Model FLOPs Utilization):
$$\text{MFU} = \frac{\text{实际 FLOPs/s}}{\text{硬件 peak FLOPs/s}} = \frac{6 \cdot N \cdot B \cdot T}{\text{step\_time} \cdot \text{TFLOPs\_peak}}$$
其中 $N$ 是模型参数量、$B$ 是 batch tokens(bs × seqlen)、$T$ = 1 step。 A100 80GB 的 bf16 peak ≈ 312 TFLOPS;H100 ≈ 989 TFLOPS。 LLaMA-7B 训练在 A100 上 MFU > 50% 算合格、> 55% 优秀。
10.2开关 1:Flash Attention
原版 attention 是 O(n²) 显存 + O(n²) 计算;Flash Attention 用 tiling 把显存降到 O(n),速度也快 2-4 倍。
plugin = HybridParallelPlugin(
...,
enable_flash_attention=True, # ColossalAI 自动用 flash-attn-2 或 SDPA
)
实现:colossalai/shardformer/modeling/llama.py::llama_attention_forward 会优先调 flash_attn_func。
长序列收益最大(>= 4K 时 1.8× 加速)。
10.3开关 2:Fused LayerNorm / RMSNorm
原版 LayerNorm 在 PyTorch eager 模式下要发多个 kernel;apex 的 fused 版只发一个,速度快 2×。
plugin = HybridParallelPlugin(
...,
enable_fused_normalization=True,
)
实现:colossalai/shardformer/layer/normalization.py::FusedRMSNorm 直接调 apex C++ kernel。
LLaMA 有 64 个 RMSNorm,开了这个开关 step 时间能减 5%-8%。
10.4开关 3:Fused QKV 投影
原版 Attention 的 q_proj / k_proj / v_proj 是三个独立 Linear,发三个 GEMM kernel。Fused QKV 把它们合并成一次 GEMM。
plugin = HybridParallelPlugin(
...,
enable_jit_fused=True,
)
实现:colossalai/shardformer/layer/qkv_fused_linear.py。
注意有些模型(特别是 GQA 的 K/V head 数和 Q 不一样)不能直接 fuse,需要手动指定。
10.5开关 4:Gradient Checkpointing
用计算换显存:每个 transformer block 不保存 activation,反向时重算一遍。显存能减 60-80%,速度损失 20-30%。
from colossalai.shardformer.shard import ShardConfig, GradientCheckpointConfig
gc_config = GradientCheckpointConfig(
gradient_checkpointing_ratio=0.5, # 一半的 layer 开 ckpt
# 或 num_ckpt_layers_per_stage=[2, 4, 4, 2] 显式指定
)
plugin = HybridParallelPlugin(
...,
gradient_checkpoint_config=gc_config,
)
关键参数 gradient_checkpointing_ratio:
- 0.0 = 不开 ckpt(最快但最费显存);
- 0.5 = 开一半(推荐起点);
- 1.0 = 全开(最省显存但慢)。
10.6开关 5:Chunked Sequence All-Reduce
开 TP 后每层 attention/MLP 都有 all-reduce,short seq 时通信比 = 计算/通信 太低(小通信 latency 主导)。 解决办法:把 sequence 切 chunk,依次执行 + overlap 通信和计算。
# 在 enable_sequence_parallelism + split_gather 模式下自动启用
plugin = HybridParallelPlugin(
...,
enable_sequence_parallelism=True,
sequence_parallelism_mode="split_gather",
)
10.7开关 6:BF16 / FP8
bf16 在 A100/H100 上 throughput 是 fp32 的 2×,比 fp16 数值范围更稳定(不会溢出)。
ColossalAI 全面支持 bf16;fp8 在 ShardFormer 里部分支持(FP8Linear),需要 H100。
# bf16(推荐)
plugin = HybridParallelPlugin(precision="bf16")
# fp8(实验性,H100 only)
plugin = HybridParallelPlugin(precision="fp8")
10.8开关 7:Zero-Bubble Pipeline
1F1B 调度下的气泡比 $(p-1)/m$,pp=4、micro_batch=8 时 ~37.5% 时间是空泡。 Zero-Bubble pipeline(2024 论文)把 backward 拆成 B_x 和 B_w 两步,能把气泡降到接近 0。
plugin = HybridParallelPlugin(
pp_size=4,
pp_style="zbv", # zero-bubble v-shape
num_model_chunks=2,
num_microbatches=8,
)
实现在 colossalai/pipeline/schedule/zero_bubble_pp.py,需要配 colossalai/pipeline/weight_grad_store.py 缓存 weight gradient。
10.9开关 8:Async Gradient All-Reduce
DP 之间的梯度 all-reduce 默认在 backward 完后做。打开 async 后,backward 进行中就开始 all-reduce 已完成的层,通信和计算 overlap。
plugin = HybridParallelPlugin(
...,
overlap_p2p=True, # PP 的 p2p 也 overlap
)
# Gemini 路径
plugin = GeminiPlugin(
...,
enable_async_reduce=True,
)
10.10性能调优清单
按这个顺序检查,能命中 90% 的性能问题:
| # | 检查项 | 影响 |
|---|---|---|
| 1 | bf16 / fp16 是否启用 | +50–100% 吞吐 |
| 2 | flash_attention 是否启用 | +30–80%(长序列) |
| 3 | fused norm 是否启用 | +5–10% |
| 4 | TP size 是否过大(> 8) | 通信瓶颈 |
| 5 | 是否在显存够时还开了 Gemini | 用 HybridParallel 更快 |
| 6 | micro_batch 数 vs PP stage 数比例 | 气泡比 |
| 7 | gradient checkpoint ratio 是否过高 | 显存够就关掉 |
| 8 | data loader 是否成为瓶颈 | 看 GPU SM 利用率 |
10.11profile:用 PyTorch Profiler
from torch.profiler import profile, ProfilerActivity, schedule, tensorboard_trace_handler
with profile(
activities=[ProfilerActivity.CPU, ProfilerActivity.CUDA],
schedule=schedule(wait=1, warmup=2, active=3, repeat=1),
on_trace_ready=tensorboard_trace_handler("./tb_log"),
) as prof:
for i, batch in enumerate(dl):
loss = model(**batch).loss
booster.backward(loss, optimizer)
optimizer.step()
prof.step()
if i >= 6: break
# 在另一终端 tensorboard --logdir tb_log
看 timeline,重点观察:
- kernel 之间是否有大量 gap(kernel launch overhead → 用 CUDA graph 或 torch.compile);
- NCCL kernel 占比超过 30% → 通信瓶颈;
- activation recomputation 在 backward 占比超过 25% → ckpt ratio 调小。
10.12这章你需要带走的
- 性能优化在 ColossalAI 里是一堆布尔开关 + 调几个比例,没有玄学;
- 新项目 default 三连:bf16 + flash_attention + fused_normalization;
- 显存紧再开 gradient_checkpointing,ratio 从 0.5 起步;
- PP 多 stage 时优先试
zbvschedule 降气泡; - Gemini 路径单独有
enable_async_reduce,开了通信和计算 overlap; - 调优顺序:bf16 → flash_attn → fused → 评估 MFU → 看 profile → 针对性调。