一、基础概念
1.1 参数精度类型
在深度学习中,模型参数通常有以下几种精度表示:
- FP32(单精度浮点数):占用4字节,是最常用的参数精度
- FP16(半精度浮点数):占用2字节,常用于推理加速和混合精度训练
- BF16(Brain Float 16):占用2字节,在训练稳定性上优于FP16
- INT8(8位整数):占用1字节,用于量化压缩
- INT4(4位整数):占用0.5字节,极限量化场景
目前大多数预训练模型默认使用**单精度(FP32)**存储参数,这也是我们计算的基准。
1.2 存储单位换算
在进行内存计算时,需要熟悉存储单位之间的换算关系:
1 Byte(字节)= 8 bit(位)
1 KB = 1024 Bytes
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
二、推理阶段内存计算
2.1 基本计算公式
大模型推理时的基本内存占用计算公式:
推理内存占用(字节)= 参数数量 × 每个参数占用的字节数
对于单精度(FP32)参数:
推理内存占用(GB)= 参数数量(B) × 4 ÷ 1024³
2.2 实际计算案例:Qwen系列模型
以阿里通义千问Qwen系列模型为例,计算其推理内存需求:
Qwen-7B模型
- 参数量:7,000,000,000
- FP32内存:7,000,000,000 × 4 ÷ 1024³ ≈ 26.1 GB
- FP16内存:7,000,000,000 × 2 ÷ 1024³ ≈ 13.0 GB
Qwen-14B模型
- 参数量:14,000,000,000
- FP32内存:14,000,000,000 × 4 ÷ 1024³ ≈ 52.2 GB
- FP16内存:14,000,000,000 × 2 ÷ 1024³ ≈ 26.1 GB
Qwen-72B模型
- 参数量:72,000,000,000
- FP32内存:72,000,000,000 × 4 ÷ 1024³ ≈ 268.4 GB
- FP16内存:72,000,000,000 × 2 ÷ 1024³ ≈ 134.2 GB
2.3 推理时的额外内存开销
实际推理部署时,还需要考虑:
-
KV Cache:用于存储注意力机制的Key和Value
- 内存需求 = batch_size × seq_length × 2 × hidden_size × num_layers × precision_bytes
-
激活值缓存:存储前向传播的中间结果
- 约占模型参数内存的10-20%
-
框架开销:PyTorch/TensorFlow等框架的额外开销
- 约占5-10%
三、训练阶段内存计算(重点)
3.1 训练内存组成
模型训练时的内存需求远高于推理,主要包括以下几个部分:
训练总内存 = 模型参数 + 梯度 + 优化器状态 + 激活值 + 临时缓冲区
3.2 详细内存计算
3.2.1 模型参数内存
与推理阶段相同,存储原始模型参数。
3.2.2 梯度内存
每个参数都需要存储对应的梯度:
梯度内存 = 参数内存 × 1
3.2.3 优化器状态内存
Adam优化器(最常用)需要存储:
- 一阶动量(momentum):与参数同样大小
- 二阶动量(variance):与参数同样大小
Adam优化器内存 = 参数内存 × 2
SGD优化器(带动量):
SGD优化器内存 = 参数内存 × 1
3.2.4 激活值内存
激活值内存与批次大小、序列长度密切相关:
激活值内存 ≈ batch_size × seq_length × hidden_size × num_layers × 系数
其中系数通常在10-20之间,取决于模型架构。
3.3 训练内存计算公式汇总
使用Adam优化器的FP32训练:
总内存 = 参数内存 × (1 + 1 + 2) + 激活值内存
总内存 ≈ 参数内存 × 4 + 激活值内存
使用混合精度训练(FP16 + FP32):
总内存 = FP16参数 + FP32参数备份 + FP16梯度 + FP32优化器状态 + 激活值
总内存 ≈ 参数量 × (2 + 4 + 2 + 8) = 参数量 × 16字节
3.4 Qwen模型训练内存实例
以Qwen-7B为例,计算不同训练配置下的内存需求:
全精度训练(FP32 + Adam)
基础计算:
- 模型参数:26.1 GB
- 梯度:26.1 GB
- Adam状态:52.2 GB(momentum + variance)
- 小计:104.4 GB
加上激活值(batch_size=1, seq_len=2048):
- 激活值:约15-20 GB
- 总计:约120-125 GB
混合精度训练(FP16 + Adam)
基础计算:
- FP16模型参数:13.0 GB
- FP32主权重:26.1 GB(用于优化器更新)
- FP16梯度:13.0 GB
- FP32 Adam状态:52.2 GB
- 小计:104.3 GB
加上激活值(batch_size=1, seq_len=2048):
- 激活值:约10-15 GB(FP16存储)
- 总计:约115-120 GB
3.5 批次大小对内存的影响
训练时批次大小直接影响激活值内存:
| 模型 | batch_size | seq_length | 激活值内存(约) | 总训练内存(约) |
|---|---|---|---|---|
| Qwen-7B | 1 | 2048 | 15 GB | 120 GB |
| Qwen-7B | 2 | 2048 | 30 GB | 135 GB |
| Qwen-7B | 4 | 2048 | 60 GB | 165 GB |
| Qwen-7B | 8 | 2048 | 120 GB | 225 GB |
四、Qwen系列模型内存需求对照表
4.1 推理内存需求
| 模型规模 | 参数量 | FP32推理 | FP16推理 | INT8推理 | INT4推理 |
|---|---|---|---|---|---|
| Qwen-0.5B | 0.5B | 1.9 GB | 0.9 GB | 0.5 GB | 0.2 GB |
| Qwen-1.8B | 1.8B | 6.7 GB | 3.4 GB | 1.7 GB | 0.8 GB |
| Qwen-7B | 7B | 26.1 GB | 13.0 GB | 6.5 GB | 3.3 GB |
| Qwen-14B | 14B | 52.2 GB | 26.1 GB | 13.0 GB | 6.5 GB |
| Qwen-32B | 32B | 119.2 GB | 59.6 GB | 29.8 GB | 14.9 GB |
| Qwen-72B | 72B | 268.4 GB | 134.2 GB | 67.1 GB | 33.5 GB |
4.2 训练内存需求(FP32 + Adam)
| 模型规模 | 最小训练内存 | 推荐训练内存 | 推荐GPU配置 |
|---|---|---|---|
| Qwen-0.5B | 8 GB | 16 GB | 1×RTX 3090 (24GB) |
| Qwen-1.8B | 28 GB | 40 GB | 1×A100 (40GB) |
| Qwen-7B | 120 GB | 160 GB | 2×A100 (80GB) |
| Qwen-14B | 240 GB | 320 GB | 4×A100 (80GB) |
| Qwen-32B | 550 GB | 700 GB | 8×A100 (80GB) |
| Qwen-72B | 1.2 TB | 1.5 TB | 16×A100 (80GB) |
五、训练内存优化策略
5.1 梯度累积
通过多次前向传播累积梯度,减少单次批处理的内存需求:
effective_batch_size = gradient_accumulation_steps × micro_batch_size
5.2 梯度检查点(Gradient Checkpointing)
牺牲计算时间换取内存,可减少约30-50%的激活值内存:
model.gradient_checkpointing_enable()
5.3 DeepSpeed ZeRO优化(重点)
5.3.1 为什么需要ZeRO?
在传统的数据并行训练中,每个GPU都需要保存完整的模型参数、梯度和优化器状态,这导致了严重的内存冗余。例如,使用2个GPU训练Qwen-7B时,传统方法每个GPU都需要120GB内存,总共需要240GB。
5.3.2 ZeRO的核心原理
ZeRO(Zero Redundancy Optimizer)通过分片技术消除内存冗余:
传统数据并行 vs ZeRO对比:
传统数据并行(2个GPU):
GPU0: [完整参数][完整梯度][完整优化器状态][激活值]
GPU1: [完整参数][完整梯度][完整优化器状态][激活值]
冗余度:100%
ZeRO-3(2个GPU):
GPU0: [一半参数][一半梯度][一半优化器状态][激活值]
GPU1: [另一半参数][另一半梯度][另一半优化器状态][激活值]
冗余度:0%
5.3.3 ZeRO的三个优化阶段
ZeRO-1:优化器状态分片
- 只分片优化器状态(Adam的momentum和variance)
- 通信开销:最小
- 内存节省:优化器状态减少N倍
ZeRO-2:优化器状态+梯度分片
- 分片优化器状态和梯度
- 通信开销:中等
- 内存节省:优化器状态和梯度都减少N倍
ZeRO-3:全分片(优化器+梯度+参数)
- 分片所有组件
- 通信开销:最大
- 内存节省:所有组件都减少N倍
5.3.4 Qwen-7B实例:从160GB降到80GB
以Qwen-7B在**2×A100 (80GB)**上训练为例,展示ZeRO如何减少内存:
原始内存需求(单GPU):
模型参数: 26.1 GB
梯度: 26.1 GB
Adam优化器: 52.2 GB(momentum + variance)
激活值: 15.6 GB
总计: 120.0 GB
使用ZeRO后每个GPU的内存需求:
| 优化级别 | 参数 | 梯度 | 优化器 | 激活值 | 每GPU总计 | 节省比例 |
|---|---|---|---|---|---|---|
| 无优化 | 26.1 GB | 26.1 GB | 52.2 GB | 15.6 GB | 120.0 GB | 0% |
| ZeRO-1 | 26.1 GB | 26.1 GB | 26.1 GB | 15.6 GB | 93.9 GB | 22% |
| ZeRO-2 | 26.1 GB | 13.0 GB | 26.1 GB | 15.6 GB | 80.8 GB | 33% |
| ZeRO-3 | 13.0 GB | 13.0 GB | 26.1 GB | 15.6 GB | 67.7 GB | 44% |
结论:使用ZeRO-3,Qwen-7B可以从120GB降到67.7GB,完美适配A100-80GB!
5.3.5 ZeRO-3的工作流程
# ZeRO-3训练伪代码
for batch in dataloader:
# 1. 前向传播:从其他GPU收集需要的参数分片
gather_params_from_other_gpus()
output = model.forward(batch)
# 2. 反向传播:计算梯度并立即分片
loss.backward()
scatter_gradients_to_owner_gpus()
# 3. 优化器更新:每个GPU只更新自己拥有的参数分片
optimizer.step() # 只更新本地分片
# 4. 参数同步:通过all-gather确保所有GPU看到更新后的参数
synchronize_params()
5.3.6 ZeRO-Offload:突破GPU内存限制
ZeRO-Offload进一步将部分数据卸载到CPU内存和NVMe SSD:
GPU内存: [激活值] [部分参数]
CPU内存: [优化器状态] [部分梯度]
NVMe SSD: [检查点] [临时数据]
Qwen-7B使用ZeRO-Offload后:
- GPU内存需求:降至40-50GB
- CPU内存需求:60-80GB
- 可在单张A100-40GB上训练!(速度会慢30-50%)
5.3.7 内存优化效果总结
Qwen系列模型使用DeepSpeed ZeRO的内存优化效果:
| 模型 | 原始内存需求 | 2×GPU (ZeRO-3) | 4×GPU (ZeRO-3) | 8×GPU (ZeRO-3) | 节省比例 |
|---|---|---|---|---|---|
| Qwen-1.8B | 28 GB | 20 GB/GPU | 15 GB/GPU | 12 GB/GPU | 28-57% |
| Qwen-7B | 120 GB | 68 GB/GPU | 42 GB/GPU | 28 GB/GPU | 43-77% |
| Qwen-14B | 240 GB | 135 GB/GPU | 84 GB/GPU | 56 GB/GPU | 44-77% |
| Qwen-32B | 550 GB | 308 GB/GPU | 192 GB/GPU | 128 GB/GPU | 44-77% |
| Qwen-72B | 1200 GB | 672 GB/GPU | 420 GB/GPU | 280 GB/GPU | 44-77% |
关键发现:
- 使用2个GPU可节省约44%内存
- 使用4个GPU可节省约65%内存
- 使用8个GPU可节省约77%内存
- GPU数量越多,内存节省越显著
5.4 量化感知训练(QAT)
使用INT8或更低精度进行训练,显著降低内存需求。
六、Python实现:训练内存计算器
class ModelMemoryCalculator:
"""大模型内存计算器"""
def __init__(self, model_name="Qwen-7B", params_in_billions=7):
self

文章讲述了如何计算13亿和7亿个单精度参数所占用的存储空间,每个单精度参数占4个字节,分别计算出为48.3GB和26.1GB。

1813

被折叠的 条评论
为什么被折叠?



