数据截至 (上游 commit f1e2ace65149)
04 · 多 GPU 与混合精度
这一章讲什么: 把单卡 bf16 训练做「对」、把多卡训练做「快」的全部工程细节。两条线: 数值线(bf16 + fp32 master + 随机舍入)和通信线(NCCL、DDP、ZeRO-1),最后落在训练一步的完 整编排与断点续训上。
1. 它要解决的小问题
- bf16 只有 8 位尾数,直接拿它做
w -= lr * update:当 update 远小于 w 时,更新量会被舍入 吞掉,训练悄悄停滞。怎么既享受 bf16 的算力又不丢精度? - 多卡各算各的梯度,怎么合?通信怎么不堵在反向传播后面?
2. 数值线:bf16 + fp32 master + 随机舍入
2.1 三种精度的分工
| 数据 | 精度 | 在哪 |
|---|---|---|
| 权重、激活、梯度 | bf16(floatX,llmc/cuda_common.h:90-91) | 前向/反向的全部 kernel |
| master 权重 | fp32(model->master_weights,train_gpt2.cu:300) | 只被优化器读写 |
| 优化器状态 m/v | fp32 | gpt2_allocate_state(train_gpt2.cu:404-409) |
| LayerNorm 的 mean/rstd、losses | fp32 | 激活 struct 里这几个字段是 float*(train_gpt2.cu:185-191) |
| matmul 累加 | fp32(cuBLAS compute type) | llmc/matmul.cuh:126 |
即「存储和传输 bf16,累加和状态 fp32」——bf16 的动态范围够大(指数位与 fp32 相同),但尾 数短,所以凡是「很多小数累加成大数」的地方都必须回到 fp32。