大模型训练与推理优化
1. GPU 时间计算基础
1.1 GPU 计算中的基本概念
h:hidden size,隐藏维度L:Transformer Block 层数V:词表大小- 参数量、FLOPs、显存和训练时间之间存在直接联系
1.2 Transformer 模型参数计算
1.2.1 Self-Attention 参数
- Q、K、V 投影矩阵:
Wq / Wk / Wv - 输出投影矩阵:
Wo - 总参数量:
4h² + 4h - 当 hidden size
h固定时,多头数量通常不会改变总参数量
1.2.2 MLP 参数
- 经典结构:
h → 4h → h - 第一层参数:
4h² + 4h - 第二层参数:
4h² + h - 总参数量:
8h² + 5h - 经典结构下,MLP 参数量约为 Attention 的 2 倍
1.2.3 LayerNorm 与单个 Transformer Block
- 一个 LayerNorm 包含
γ和β,参数量为2h - 一个 Block 通常包含两个 LayerNorm,共
4h - Self-Attention:
4h² + 4h - MLP:
8h² + 5h - LayerNorm:
4h
因此单个 Transformer Block:
12h² + 13h
当h较大时,可以近似为:
12h²
1.2.4 整个 Transformer 模型参数
L个 Transformer Block:L × (12h² + 13h)- Embedding Matrix:
V × h
因此总参数量可以近似表示为:
N ≈ Vh + L(12h² + 13h)
进一步简化:
N ≈ Vh + 12Lh²
核心关系可以记成:
Attention ≈ 4h²
MLP ≈ 8h²
一个 Block ≈ 12h²
因此 Transformer 参数量主要随着 hidden sizeh的平方增长。
1.2.5 用12Lh²快速估算 LLaMA 参数量
上一节得到:
一个 Transformer Block ≈ 12h²
如果模型共有L个 Transformer Block,那么主体参数量可以近似为:
N ≈ 12Lh²
其中:
h:hidden sizeL:Transformer 层数N:Transformer 主体参数量
以 LLaMA 7B 为例:
h = 4096L = 32
代入:
12 × 32 × 4096² ≈ 6.44B
而 LLaMA 7B 的实际参数规模约为6.7B,说明这个公式可以比较方便地估算模型大概属于多少 B。
不同规模可以快速估算为:
| 模型 | hidden sizeh | 层数L | 12Lh²估算 | 实际规模 |
|---|---|---|---|---|
| LLaMA 7B | 4096 | 32 | 6.44B | 约 6.7B |
| LLaMA 13B | 5120 | 40 | 12.58B | 约 13.0B |
| LLaMA 33B | 6656 | 60 | 31.90B | 约 32.5B |
| LLaMA 65B | 8192 | 80 | 64.42B | 约 65.2B |
可以看到,估算值与实际参数规模已经非常接近。
1.2.6 为什么估算值和实际参数量不完全一致
12Lh²主要估算 Transformer Block 的主体参数,并不是完整模型的精确参数公式。
实际模型还包括:
- Token Embedding
- LM Head
- 最后的 RMSNorm
- SwiGLU 的具体中间维度
- Attention 的具体实现
例如 LLaMA 7B:
Embedding ≈ V × h
当:
V ≈ 32000
h = 4096
则:
Embedding ≈ 32000 × 4096 ≈ 131M
因此:
12Lh²
更适合用来快速判断模型规模,而不是精确计算模型的每一个参数。
1.2.7 参数规模的增长规律
由:
N ≈ 12Lh²
可以直接看出:
L × 2→ 参数量大约× 2h × 2→ 参数量大约× 4
也就是说,层数L对参数量是线性影响,而 hidden sizeh对参数量是平方影响。
核心关系可以记成:
一个 Block ≈ 12h²
L 个 Block ≈ 12Lh²
代入 h 和 L → 快速判断模型大概是几 B
12Lh²是 Transformer 主体参数的快速估算公式,不是 LLaMA 的精确参数公式。
1.3 参数量与显存占用
- 模型参数本身需要占用 GPU 显存
- FP32、FP16、BF16 每个参数占用空间不同
- 训练阶段还需要保存 Gradient 和 Optimizer State
- 参数量并不等于实际训练显存占用
1.4 参数量与计算量
1.4.1 FLOP 与 FLOPs
FLOP:一次浮点运算- 一次乘法约为
1 FLOP - 一次加法约为
1 FLOP FLOPs:通常用来表示完成某个计算需要多少浮点运算GPU FLOPS:GPU 每秒能够完成多少浮点运算
因此训练时间可以先粗略理解为:
训练时间 ≈ 总 FLOPs / GPU 实际计算速度
1.4.2 向量点积的计算量
假设两个长度为m的向量:
x = (x1, x2, ..., xm)
y = (y1, y2, ..., ym)
它们做点积时需要:
m次乘法m - 1次加法
因此:
FLOPs = m + (m - 1) = 2m - 1
当m很大时,可以近似为:
向量点积 ≈ 2m FLOPs
1.4.3 矩阵乘法的计算量
假设:
A:m × n
B:n × r
那么:
C = A × B
结果矩阵C的大小为:
m × r
其中每一个元素,都是一次长度为n的向量点积:
一个元素 ≈ 2n FLOPs
而C一共有:
m × r
个元素,因此:
矩阵乘法 FLOPs ≈ (m × r) × 2n
整理得到:
FLOPs ≈ 2mnr
这是后面计算 Transformer FLOPs 最重要的基础公式。
1.4.4 参数量和 FLOPs 的区别
以 Transformer 中的 Q 投影为例:
Q = XWq
假设:
X:s × h
Wq:h × h
其中:
s:Sequence Length / Token 数量h:hidden size
Wq本身包含:
h × h = h²
个参数,因此:
参数量 = h²
但是实际计算时:
(s × h) × (h × h)
根据矩阵乘法公式:
FLOPs ≈ 2 × s × h × h
所以:
Q 投影 FLOPs ≈ 2sh²
可以看到:
参数量:h²
计算量:2sh²
多出来的s,是因为同一组权重参数需要被s个 Token 重复使用。
1.4.5 核心关系
这一部分可以记住两条公式:
长度为 m 的向量点积 ≈ 2m FLOPs
(m × n) × (n × r) 矩阵乘法 ≈ 2mnr FLOPs
后面计算 Transformer 时:
- Q、K、V 投影
- Attention
- 输出投影
Wo - MLP
本质上都可以继续使用这个矩阵乘法公式。
因此整体逻辑就变成:
参数量 → 矩阵乘法 → FLOPs → GPU FLOPS → 训练时间
1.4.6 Self-Attention 的输入与 Q、K、V 计算量
设输入:
X ∈ R^(b × s × h)
其中:
b:batch sizes:sequence lengthh:hidden size
Self-Attention 首先计算:
Q = XWq
K = XWk
V = XWv
其中:
Wq、Wk、Wv ∈ R^(h × h)
以 Q 为例:
[b,s,h] × [h,h]
根据矩阵乘法:
FLOPs ≈ 2mnr
得到:
Q ≈ 2bsh² FLOPs
因此 Q、K、V 三个投影一共:
QKV ≈ 6bsh² FLOPs
1.4.7 Attention Score 与 V 的计算量
Q、K 的形状都是:
[b,s,h]
计算:
QK^T
相当于:
[s,h] × [h,s]
因此:
QK^T ≈ 2bs²h FLOPs
这里出现s²,是因为每一个 Token 都需要与其他 Token 计算相关性。
所以标准 Self-Attention 对序列长度具有:
O(s²)
的计算复杂度。
经过 Softmax 后,Attention 权重矩阵形状为:
A:[b,s,s]
再计算:
A × V
即:
[s,s] × [s,h]
因此:
Attention × V ≈ 2bs²h FLOPs
严格来说,Scaled Dot-Product Attention 的缩放因子是
1 / √d_head,不是1 / √h。
1.4.8 输出投影与 Self-Attention 总 FLOPs
Attention 的输出仍然为:
[b,s,h]
最后还需要经过输出投影:
Wo ∈ R^(h × h)
因此:
Wo ≈ 2bsh² FLOPs
把 Self-Attention 的主要计算加起来:
Q、K、V:6bsh²
QK^T:2bs²h
Attention × V:2bs²h
Wo:2bsh²
因此:
Self-Attention FLOPs ≈ 8bsh² + 4bs²h
通常这里暂时忽略 Softmax、缩放、Bias 和残差连接等较小计算。
1.4.9 Self-Attention FLOPs 的核心规律
Self-Attention 的计算量可以拆成两部分:
8bsh²
来自:
Q、K、V、Wo
也就是线性投影计算。
而:
4bs²h
来自:
QK^T + Attention × V
也就是 Token 之间的 Attention 计算。
因此可以记成:
Self-Attention ≈ 8bsh² + 4bs²h
其中:
h²:主要来自线性层s²:主要来自 Token 与 Token 之间的 Attention
所以:
h越大 → 线性层越贵
s越长 → Attention 的平方项越贵
这也为后面理解 Flash Attention、KV Cache 和长上下文优化做准备。
1.4.10 MLP 的 FLOPs 计算
经典 Transformer 的 MLP 一般采用:
h → 4h → h
输入:
X:[b,s,h]
第一层:
[b,s,h] × [h,4h]
根据矩阵乘法:
FLOPs ≈ 2mnr
得到:
第一层 MLP ≈ 8bsh²
第二层:
[b,s,4h] × [4h,h]
同样得到:
第二层 MLP ≈ 8bsh²
因此整个 MLP:
MLP FLOPs ≈ 16bsh²
这里通常忽略 GELU、Bias、LayerNorm 和残差相加等较小计算。
1.4.11 单个 Transformer Block 的 FLOPs
上一节得到:
Self-Attention ≈ 8bsh² + 4bs²h
而:
MLP ≈ 16bsh²
所以一个 Transformer Block:
Block FLOPs
≈ (8bsh² + 4bs²h) + 16bsh²
整理得到:
Block FLOPs ≈ 24bsh² + 4bs²h
其中:
24bsh²:Q、K、V、Wo 和 MLP 等线性层计算4bs²h:QK^T 和 Attention × V 的 Token-Token 计算
因此:
一个 Block ≈ 24bsh² + 4bs²h
1.4.12 L 个 Transformer Block 的计算量
如果模型共有L个 Transformer Block:
L 个 Block FLOPs
≈ L(24bsh² + 4bs²h)
这里:
b:batch sizes:sequence lengthh:hidden sizeL:Transformer Block 数量
1.4.13 输出到词表的计算量
最后一个 Transformer Block 输出:
[b,s,h]
模型还需要通过 LM Head 将 hidden state 映射到整个词表:
[b,s,h] × [h,V]
其中:
V = vocabulary size
因此:
LM Head FLOPs ≈ 2bshV
所以整个模型一次前向传播的主要计算量可以写成:
Forward FLOPs ≈ L(24bsh² + 4bs²h) + 2bshV
1.4.14 参数量与前向 FLOPs 的关系
前面计算参数量时得到:
一个 Transformer Block ≈ 12h²
而一个 Block 中主要线性层的前向计算量约为:
24bsh²
可以写成:
24bsh² = 2bs × 12h²
也就是说:
前向 FLOPs ≈ 2 × Token 数量 × 参数量
这里一个 batch 的 Token 数量为:
b × s
因此可以粗略理解为:
每个参数在处理每个 Token 时,通常会参与一次乘加运算,而一次乘加约对应 2 FLOPs。
这也是后面推导:
Training FLOPs ≈ 6ND
的重要基础。
1.4.15 这一部分的核心关系
从前面的计算可以串成:
矩阵乘法 ≈ 2mnr
↓
Self-Attention ≈ 8bsh² + 4bs²h
↓
MLP ≈ 16bsh²
↓
一个 Block ≈ 24bsh² + 4bs²h
↓
L 个 Block ≈ L(24bsh² + 4bs²h)
↓
整个模型前向 ≈ L(24bsh² + 4bs²h) + 2bshV
下一步就可以继续从“前向传播 FLOPs”推到“训练 FLOPs”,也就是经典的:
Training FLOPs ≈ 6ND
1.4.16 从参数量推到前向 FLOPs
前面已经得到:
一个 Transformer Block 参数量 ≈ 12h²
如果模型共有L个 Block:
N ≈ 12Lh²
其中:
N:模型参数量L:Transformer Block 数量h:hidden size
对于一个 batch:
Token 数量 = b × s
前面又得到,一个 Block 的主要线性计算约为:
24bsh²
因此L个 Block:
Forward FLOPs ≈ 24Lbsh²
注意:
24Lbsh² = 2 × (12Lh²) × bs
也就是:
Forward FLOPs ≈ 2 × 参数量 × Token 数量
如果整个训练过程一共处理D个 Token:
Forward FLOPs ≈ 2ND
其中:
N:模型参数量D:训练 Token 总数
1.4.17 为什么前向传播是2ND
可以把一个参数参与计算理解成一次乘加:
x × w → 1 次乘法
结果累加 → 1 次加法
因此:
1 次乘法 + 1 次加法 ≈ 2 FLOPs
所以:
一个参数 × 一个 Token ≈ 2 FLOPs
进一步得到:
N 个参数 × D 个 Token ≈ 2ND FLOPs
因此:
Forward FLOPs ≈ 2ND
1.4.18 为什么训练变成6ND
训练不仅包含 Forward,还需要 Backward。
对于一个线性层:
Y = XW
前向传播主要计算:
Y = XW
可以看成1份矩阵乘法计算。
反向传播主要还需要计算:
dX = dY · W^T
以及:
dW = X^T · dY
因此可以粗略理解成:
Forward ≈ 1 份
Backward ≈ 2 份
所以完整训练:
Forward + Backward ≈ 3 × Forward
而:
Forward ≈ 2ND
因此:
Training FLOPs ≈ 3 × 2ND
最终得到:
Training FLOPs ≈ 6ND
1.4.196ND的核心直觉
对于:
一个参数 × 一个 Token
可以近似理解为:
Forward ≈ 2 FLOPs
Backward:输入梯度 ≈ 2 FLOPs
Backward:参数梯度 ≈ 2 FLOPs
所以:
完整训练 ≈ 2 + 2 + 2 = 6 FLOPs
最终可以记成:
推理 / Forward FLOPs ≈ 2ND
训练 FLOPs ≈ 6ND
这里的6ND是大模型训练计算量的快速估算公式,并不是严格恒等式。
它主要统计参数矩阵乘法带来的主要计算,而像:
QK^TAttention × V- Softmax
- 激活函数
- LayerNorm
等额外计算没有被完整包含。
因此它更适合用于:
快速估算大模型预训练需要多少计算量
而不是精确计算每一次运算。
1.5 从训练 FLOPs 到训练时间
1.5.1 训练时间的基本公式
前面已经得到训练总计算量:
Training FLOPs ≈ 6ND
其中:
N:模型参数量D:训练 Token 总数
课程中有时也会使用:
Training FLOPs ≈ 8ND
作为更保守的经验估算,把部分额外计算也考虑进去。
训练时间本质上就是:
训练时间 = 总计算量 / 实际计算速度
因此可以写成:
Time ≈ C / (G × P × U)
其中:
C:训练总 FLOPsG:GPU 数量P:单张 GPU 峰值 FLOP/sU:GPU 有效利用率
如果按照课程中的8ND:
Time ≈ 8ND / (G × P × U)
1.5.2 GPU FLOPS 与实际计算速度
GPU 标称的 TFLOPS 表示理论峰值计算速度。
例如:
312 TFLOPS
表示:
312 × 10^12 FLOP/s
但真实训练时通常无法持续达到峰值,因为还会受到:
- GPU 间通信
- 数据加载
- 显存访问
- 梯度同步
- 非矩阵计算
等因素影响。
因此实际有效算力可以近似写成:
Effective FLOPS = G × P × U
这里的U更接近训练中的MFU(Model FLOPs Utilization),而不是简单的 GPU 使用率。
1.5.3 一个 7B 模型的训练时间估算
假设:
- 模型参数:
N = 7B = 7 × 10^9 - 训练数据:
D = 2T = 2 × 10^12 Token - GPU 数量:
G = 1000 - 单卡峰值算力:
P = 312 TFLOP/s - 有效利用率:
U = 45%
按照课程中的:
C ≈ 8ND
得到:
C ≈ 8 × 7×10^9 × 2×10^12
≈ 1.12 × 10^23 FLOPs
实际总计算速度:
G × P × U
= 1000 × 312×10^12 × 0.45
≈ 1.404 × 10^17 FLOP/s
因此:
Time ≈ 1.12×10^23 / 1.404×10^17
≈ 7.98 × 10^5 s
换算后:
≈ 9.2 天
所以在这些理想化假设下:
7B + 2T Tokens + 1000 张 GPU
训练时间大约是:
9 天左右
1.5.4 为什么增加 GPU 不一定线性加速
理论上:
GPU × 2 → 计算速度 × 2 → 时间 ÷ 2
但实际训练还存在:
- All-Reduce 通信
- GPU 同步等待
- Pipeline Bubble
- 网络带宽限制
- 数据加载与 Checkpoint
因此:
实际加速比 < GPU 数量增长比例
这也是后面需要学习 Distributed Training 的原因。
1.5.5 常见单位换算
1B = 10^91T Token = 10^12 Token1 TFLOP/s = 10^12 FLOP/s
因此做训练时间估算时,一定先统一单位。
1.5.6 从参数量到训练时间的完整链路
整套逻辑可以记成:
参数量 N
↓
训练 Token 数 D
↓
训练计算量 ≈ 6ND(或课程中使用 8ND)
↓
实际算力 = GPU 数 × 单卡峰值 FLOPS × 有效利用率
↓
训练时间 = 总 FLOPs / 实际 FLOPS
也就是:
N、D 决定有多少活
G、P、U 决定每秒能干多少活
最后:
Time ≈ C / (G × P × U)
1.5.7 训练时间实战:175B + 300B Tokens
假设:
- 模型参数量:
N = 175B = 175 × 10^9 - 训练 Token:
D = 300B = 300 × 10^9 - GPU 数量:
G = 1024 - 单张 A100 峰值算力:
P = 312 TFLOP/s - 有效利用率:
U = 0.45
课程继续采用:
Training FLOPs ≈ 8ND
因此总训练计算量:
C ≈ 8 × 175×10^9 × 300×10^9
得到:
C ≈ 4.2 × 10^23 FLOPs
1.5.8 计算 GPU 集群的实际算力
单张 A100 峰值算力:
312 TFLOP/s
考虑 45% 的有效利用率:
312 × 0.45 ≈ 140.4 TFLOP/s
1024 张 GPU:
1024 × 312×10^12 × 0.45
得到:
≈ 1.44 × 10^17 FLOP/s
因此整个 GPU 集群每秒实际能够完成约:
1.44 × 10^17
次浮点运算。
1.5.9 计算最终训练时间
根据:
训练时间 = 总计算量 / 实际总算力
代入:
Time ≈ 4.2×10^23 / 1.44×10^17
得到:
≈ 2.92 × 10^6 秒
换算成天:
2.92 × 10^6 / 86400 ≈ 33.8 天
因此:
训练时间 ≈ 34 天
也就是说,在这些假设条件下:
175B 参数 + 300B Tokens + 1024 张 A100
大约需要:
34 天
1.5.10 GPU 数量与利用率对训练时间的影响
训练时间公式:
Time ≈ C / (G × P × U)
因此:
- GPU 数量
G增加 → 训练时间下降 - 单卡算力
P增加 → 训练时间下降 - 有效利用率
U提高 → 训练时间下降
例如利用率从:
45% → 90%
在其他条件不变时,理论训练时间大约可以减半:
34 天 → 17 天
但现实中 GPU 数量增加后,会带来更多:
- 通信
- 梯度同步
- 参数同步
- 数据传输
因此 GPU 翻倍,并不一定意味着训练时间严格减半。
1.5.116ND和8ND的区别
前面推导得到的经典估算是:
Training FLOPs ≈ 6ND
而课程这里使用:
Training FLOPs ≈ 8ND
可以这样理解:
6ND
主要估算参数矩阵乘法带来的训练计算量。
而:
8ND
属于课程中采用的更保守估算,把部分额外计算开销也考虑进去。
因此训练时间估算时,必须先确认使用的是:
6ND
还是:
8ND
因为两者会直接影响最终结果。
这一节最核心可以记成:
模型参数量 × Token 数 → 总工作量
GPU 数 × 单卡算力 × 利用率 → 实际计算速度
最终:
训练时间 = 总工作量 / 实际计算速度
1.5.12 什么是 GPU Hours
GPU Hours 表示:
GPU Hours = GPU 数量 × 实际运行小时数
例如:
1 张 GPU × 10 小时 = 10 GPU Hours
10 张 GPU × 1 小时 = 10 GPU Hours
因此 GPU Hours 更像是在描述:
总 GPU 资源消耗
而不是人真正等待了多久。
反过来,在理想情况下:
实际训练时间 ≈ GPU Hours / GPU 数量
1.5.13 GPU Hours 与实际训练时间
假设某次训练总共消耗:
3,100,000 GPU Hours
如果只使用:
1 张 GPU
那么:
训练时间 = 3,100,000 小时
换算成年:
3,100,000 / (24 × 365) ≈ 354 年
也就是大约:
355 年
如果使用更多 GPU:
100 张 GPU→ 理想约3.54 年1000 张 GPU→ 理想约129 天10000 张 GPU→ 理想约13 天
所以:
GPU 数量 ↑ → Wall-clock Time ↓
这也是为什么大模型训练必须依赖分布式训练。
1.5.14 GPU 数量增加为什么不能完全线性加速
理想情况下:
GPU × 2 → 训练时间 ÷ 2
但现实中 GPU 越多,还会增加:
- GPU 间通信
- Gradient Synchronization
- 参数同步
- 网络传输
- Pipeline Bubble
- 负载不均衡
因此实际情况通常是:
实际训练时间 > GPU Hours / GPU 数量
也就是说,GPU 数量增加以后,并不能始终保持完美的线性加速。
1.5.15 FLOPs、GPU FLOPS、GPU Hours 与训练时间
这几个概念可以这样区分:
FLOPs
表示:
整个训练任务总共需要做多少计算
例如:
4.2 × 10^23 FLOPs
GPU FLOPS
表示:
GPU 每秒能够完成多少计算
例如:
312 TFLOP/s
GPU Hours
表示:
总共消耗了多少 GPU × 小时
例如:
3,100,000 GPU Hours
Wall-clock Training Time
表示:
实际从训练开始到结束,人真正等待了多久
理想情况下:
Wall-clock Time ≈ GPU Hours / GPU 数量
但现实中还需要考虑分布式效率、通信和利用率。
1.5.16 大模型训练计算成本的完整链路
现在可以把前面的内容完整串起来:
模型参数量 N
+
训练 Token 数 D
↓
估算训练总 FLOPs
↓
结合 GPU 峰值算力与利用率
↓
估算 GPU Hours
↓
根据 GPU 数量
↓
估算 Wall-clock Training Time
可以简单记成:
FLOPs = 总共有多少活
GPU FLOPS = 每秒能干多少活
GPU Hours = 一共用了多少 GPU 资源
Wall-clock Time = 实际等了多久
因此,大模型训练真正解决的问题就是:
把巨大的总计算量,通过大量 GPU 和分布式训练尽可能高效地并行完成。