拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

大模型训练与推理优化(一)

大模型训练与推理优化(一)

大模型训练与推理优化

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 sizeh固定时,多头数量通常不会改变总参数量
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 size
  • L:Transformer 层数
  • N:Transformer 主体参数量

以 LLaMA 7B 为例:

  • h = 4096
  • L = 32

代入:

12 × 32 × 4096² ≈ 6.44B

而 LLaMA 7B 的实际参数规模约为6.7B,说明这个公式可以比较方便地估算模型大概属于多少 B。

不同规模可以快速估算为:

模型hidden sizeh层数L12Lh²估算实际规模
LLaMA 7B4096326.44B约 6.7B
LLaMA 13B51204012.58B约 13.0B
LLaMA 33B66566031.90B约 32.5B
LLaMA 65B81928064.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→ 参数量大约× 2
  • h × 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 size
  • s:sequence length
  • h: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 size
  • s:sequence length
  • h:hidden size
  • L: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^T
  • Attention × V
  • Softmax
  • 激活函数
  • LayerNorm

等额外计算没有被完整包含。

因此它更适合用于:

快速估算大模型预训练需要多少计算量

而不是精确计算每一次运算。

1.5 从训练 FLOPs 到训练时间

1.5.1 训练时间的基本公式

前面已经得到训练总计算量:

Training FLOPs ≈ 6ND

其中:

  • N:模型参数量
  • D:训练 Token 总数

课程中有时也会使用:

Training FLOPs ≈ 8ND

作为更保守的经验估算,把部分额外计算也考虑进去。

训练时间本质上就是:

训练时间 = 总计算量 / 实际计算速度

因此可以写成:

Time ≈ C / (G × P × U)

其中:

  • C:训练总 FLOPs
  • G:GPU 数量
  • P:单张 GPU 峰值 FLOP/s
  • U: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^9
  • 1T Token = 10^12 Token
  • 1 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 和分布式训练尽可能高效地并行完成。

返回列表