性能优化:compile / async TP / float8
TorchTitan 是 PyTorch 新特性最快落地的地方。开几个开关就能从 ~45% MFU 拉到 ~65%。本章把主要开关讲清楚。
9.1开关清单(按重要性)
| 开关 | 典型收益 | 条件 |
|---|---|---|
| bf16 / fp16 | +50-100% | 所有 NVIDIA GPU |
| activation_checkpoint=selective | +5% 显存 | — |
| torch.compile | +10-20% | torch 2.4+ |
| Float8(fp8 训练) | +25-40% | H100/H200 + torchao |
| async TP | +5-15% | TP > 1 |
| HSDP (replicate × shard) | +10%(跨机) | 多机 |
| Pipeline 1F1B | 显存大幅省 | 大模型 |
9.2torch.compile
[compile]
enable = true
model_backend = "inductor"
TorchTitan 对每个 TransformerBlock 单独 compile(而非整个 model),收益更大、warm-up 更快。代码在 torchtitan/distributed/parallelize_llama.py::apply_compile。
注意:
- 第一个 step 慢 5-10 倍(编译期);
- seq_len 改变会触发重编译;
- 跟 FSDP2 / TP / CP 都兼容。
9.3Float8(fp8 训练)
用 torchao 的 fp8 GEMM 替换 bf16 GEMM。仅 H100/H200/B200 上有 fp8 硬件。
[float8]
enable_float8_linear = true
recipe_name = "rowwise" # rowwise / tensorwise / mxfp8
| recipe | 说明 |
|---|---|
| tensorwise | per-tensor 缩放,最稳,最慢 |
| rowwise | per-row 缩放,常用 |
| mxfp8 | MX FP8(H100 新格式),最快 |
实现:torchao.float8.convert_to_float8_training()。把所有 nn.Linear 换成 Float8Linear,weight / activation 在 forward 之前现 quant 到 fp8 算 GEMM,结果回 bf16。
9.4async TP
普通 TP 在 attention/MLP 出口要 all-reduce,等通信完才进下一层。Async TP 把 GEMM 切成微块,每算完一块就启动该块的 reduce-scatter,让通信和计算 overlap。
[experimental]
enable_async_tensor_parallel = true
需要 PyTorch 2.5+ 且 TP > 1。典型增益 5-15%。
9.5activation checkpoint
[activation_checkpoint]
mode = "selective" # none / selective / full
selective_ac_option = "op" # op / N(数字 N 表示每 N 层选一个)
三档:
- none:不重算,最快但费显存;
- selective:只对某些"重算便宜"的算子(attention / silu / matmul)保 ckpt;
- full:每层都 ckpt,最省显存但慢 25%。
TorchTitan 推荐 selective + op,是 SAC(Selective Activation Checkpointing)方案。
9.6HSDP
多机时让跨机做 DDP-style replicate(每 N 步同步梯度),机内做 FSDP shard。
[training]
data_parallel_replicate_degree = 2 # 节点间
data_parallel_shard_degree = 8 # 节点内
典型场景:2 节点 × 8 GPU 训 70B,效果比纯 FSDP 跨机快 ~10%。
9.7性能总览(70B 配方)
Llama-3 70B、32×H100、bf16、seqlen=8K:
| 配方 | MFU | tok/s/GPU |
|---|---|---|
| FSDP2 + TP=4 baseline | ~48% | ~1,800 |
| + selective ac | ~49% | ~1,850 |
| + torch.compile | ~56% | ~2,100 |
| + async TP | ~60% | ~2,250 |
| + Float8 rowwise | ~68% | ~2,550 |
9.8调优顺序
- 先 bf16 + selective ac,跑通;
- 开 torch.compile,跑稳;
- 显存够 → 加大 batch 或减 ac;不够 → 加 TP;
- 多机:开 HSDP;
- H100:开 float8 + async TP。
9.9性能优化的源码位置
每个优化开关都对应一个文件,迷路时直接 grep:
| 优化 | 源码位置 | 核心 API |
|---|---|---|
| Async TP | torchtitan/distributed/tensor_parallel.py:102-116 | maybe_enable_async_tp() 设置 torch._inductor.config._micro_pipeline_tp = True |
| Context Parallel | torchtitan/distributed/context_parallel.py:35-80 | apply_cp_to_forward(),分 FlexAttention / SDPA 两条路 |
| FSDP2 | torchtitan/distributed/fsdp.py | fully_shard() + DataParallelMeshDims |
| Pipeline Parallel | torchtitan/distributed/pipeline_parallel.py | 1F1B + looped schedules(torch.distributed.pipelining) |
| Float8 训练 | torchtitan/components/quantization/float8.py:24-80 | Float8LinearConverter 替换 Linear;recipes: rowwise / rowwise_with_gw_hp |
| parallelize_llama | torchtitan/models/llama3/parallelize.py:41-100 | TP→CP→async_tp→AC→compile→FSDP 顺序施加 |
9.10ParallelDims:所有并行的统一抽象
看 torchtitan/distributed/parallel_dims.py:26-80:
@dataclass
class ParallelDims:
dp_replicate: int # DDP replication
dp_shard: int # FSDP shard
cp: int # Context parallel
tp: int # Tensor parallel
pp: int # Pipeline parallel
ep: int # Expert parallel (MoE)
world_size: int
full_dtensor: bool
@classmethod
def from_config(cls, cfg): ...
def get_mesh(self): ... # → torch.distributed.DeviceMesh
@property
def tp_enabled(self): ...
整个框架的 "5D + EP" 并行就是这 8 个字段。world_size = dp_replicate × dp_shard × cp × tp × pp(EP 与 TP/DP 复用 rank)。配置约束:seq_len % (tp × 2cp) == 0 在 parallelize.py 里硬校验。
9.11Float8 配方选择
| recipe | 精度 vs bf16 | 速度收益 | 用场景 |
|---|---|---|---|
rowwise | 近无损 | +15-20% | 默认 |
rowwise_with_gw_hp | 无损 | +10-15% | 梯度敏感任务 |
| tensorwise(不在 TorchTitan) | 有时损 1pp | +20-25% | 不推荐 |
注意:Float8 跳过 dim 不能被 16 整除的 Linear(看 float8.py:Float8LinearConverter 的 skip 列表),所以 vocab_size 不是 16 倍数时 lm_head 会回退 bf16。
9.12这章你需要带走的
- TorchTitan 性能优化全是 PyTorch 新特性的展览;
- 5 个核心开关:bf16 / compile / float8 / async_tp / selective_ac;
- H100/H200 必开 float8,能从 ~50% MFU 推到 ~65%+;
- 多机用 HSDP 而非纯 FSDP。