GPU 显存
LLM 显存分析
【2023-8-30】大模型要占你多少内存?这个神器一键测量,误差低至0.5MB,免费可用
大模型训练推理要用多少内存?
- HuggingFace Space 最新火起来工具——Model Memory Calculator,模型内存测量器,在网页端人人可体验。
- 比如模型bert-base-case Int8估计占用413.18 MB内存,实际占用为413.68MB,相差0.5MB,误差仅有0.1%。
实际推理过程,EleutherAI 发现需要在预测数据基础上,预留 20% 内存
经验
显存不够
【2023-8-30】baichuan-7b (14G) 部署失败,空间不够
- GPU: A30, 24G 显存
错误信息:
torch.cuda.OutOfMemoryError: CUDA out of memory. Tried to allocate 86.00 MiB (GPU 0; 22.20 GiB total capacity; 7.47 GiB already allocated; 51.12 MiB free; 7.48 GiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF
显存工具
Model Memory Calculator
Memory Usage for ‘baichuan-inc/Baichuan-7B’
dtype | Largest Layer or Residual Group | Total Size | Training using Adam |
---|---|---|---|
float32 | 1000.0 MB | 26.2 GB | 104.82 GB |
float16/bfloat16 | 500.0 MB | 13.1 GB | 52.41 GB |
int8 | 250.0 MB | 6.55 GB | 26.2 GB |
int4 | 125.0 MB | 3.28 GB |
LLM Check
显存估算开源项目:
LLM 参数分析
只有参数层占用显存。
这部份显存占用和输入无关,模型加载完成之后就会占用。
有参数层
有参数层主要包括:
- 卷积
- 全连接
- BatchNorm
- Embedding层
- … …
无参数层:
- 多数的激活层(Sigmoid/ReLU)
- 池化层
- Dropout
- … …
模型参数数目(不考虑偏置项b)为:
- Linear(M->N): 参数数目:M×N
- Conv2d(Cin, Cout, K): 参数数目:Cin × Cout × K × K
- BatchNorm(N): 参数数目: 2N
- Embedding(N,W): 参数数目: N × W
参数占用显存 = 参数数目 × n
- n = 4 :float32
- n = 2 : float16
- n = 8 : double64
PyTorch中,当执行完 model=MyGreatModel().cuda()
后就会占用相应显存,占用显存大小基本与上述分析的显存差不多(会稍大一些,因为其它开销)。
GPU 显存占用
GPU 要存哪些参数
【2023-6-28】参考
模型训练中,GPU 要存储的参数
- 模型本身的参数、优化器状态、激活函数的输出值、梯度、一些零时的Buffer
微调时,显存占用组成:
- 1、参数占用: 微调时一般采用
bf16
/fp16
格式来训练,1个参数需要2字节显存,那10亿参数所需的显存就大概为2G左右。- 13B 模型,bf16参数占用的显存就至少为2*13=26GB
- 2、梯度占用: 每个参数对应一个梯度,所以梯度显存占用等于模型参数的占用:26GB。
- 3、优化器: 采用AdamW优化器(bitsandbytes版本), 为每个参数计算两个状态变量v和r,显存占用就为26*2=52GB,同时优化器还会为模型参数维护一个float32的副本,占用26 * 2=52G。
- 更新:如果是deepspeed版本的优化器,还会保存一份float32的梯度,额外占用26 * 2=52G的显存。实现代码在这里
- 4、激活值: 不同 batch size和sequence length会影响显存占用
- 以Llama-13B为例,batch-size=1,sequence length=2048条件下,激活值得占用大概为:17gb
- Batch Size 和 Sequence Length:直接影响激活值的显存占用。
- 框架和库的开销:如 PyTorch, TensorFlow, CUDA kernels 等会占用一部分固定或可变的显存。
13B 模型, 混合精度,全参数微调, 所需显存至少为
- 26+26+52+52+17=173GB
这只是 bs=1 时的粗略估计,不是很准确,还有一些额外开销没有包括在内。
通常训练时,batch不能取太小,常见的模型训练batch size都是成百上千的,这显存占用可就是天文数字了。
模型参数仅占所有数据的小部分
- 当进行混合精度运算时,模型状态参数(优化器状态 + 梯度+ 模型参数)占大半以上。
因此,要想办法去除模型训练过程中的冗余数据。
梯度与动量
优化器
- SGD:W_t+1 = W_t - α * ▽ F(W_t)
- 除了保存权重W, 还要保存对应的梯度 ▽ F(W_t) ,因此, 显存占用等于参数占用显存 x2
- 带Momentum-SGD:
- v_t+1 = ρv_t + ▽ F(W_t)
- W_t+1 = W_t - α * v_t+1
- 还需要保存动量, 因此显存 x3
- Adam优化器
- 动量占用的显存更多,显存x4
总结,模型中与输入无关的显存占用包括:
- 参数 W
- 梯度 dW(一般与参数一样)
- 优化器的动量
- 普通SGD没有动量,momentum-SGD动量与梯度一样,Adam优化器动量的数量是梯度的两倍
输入输出
以CNN为例,模型输出的显存占用,总结如下:
- 需要计算每一层的feature map的形状(多维数组的形状)
- 需要保存输出对应的梯度用以反向传播(链式法则)
- 显存占用与 batch size 成正比
- 模型输出不需要存储相应的动量信息。
深度学习中神经网络的显存占用,可以得到如下公式:
显存占用 = 模型显存占用 + batch_size × 每个样本的显存占用
显存不是和batch-size简单的成正比,尤其是模型自身比较复杂的情况下:比如全连接很大,Embedding层很大
另外需要注意:
- 输入(数据,图片)一般不需要计算梯度
- 神经网络每层输入/输出都需要保存下来,用来反向传播,但是在某些特殊的情况下,不要保存输入。
- 比如 ReLU,PyTorch中,使用nn.ReLU(inplace = True) 能将激活函数ReLU的输出直接覆盖保存于模型的输入之中,节省不少显存。
- 这时候是如何反向传播? (提示:y=relu(x) -> dx = dy.copy();dx[ y<=0 ] =0)
显存预估
总结
模型规模 | 参数 | 梯度 | 激活值 | 总数 | 训练方案 |
---|---|---|---|---|---|
7B | 12 * 7 = 84 GB | >100 GB | 2*A100 (80GB),并配合 DeepSpeed ZeRO Stage 2/3 | ||
70B | 12 * 70 = 840 GB | 远超 1 TB | 大规模的 GPU 集群 | ||
微调方式
方式
- 全参微调: (Full Fine-tuning) 模型所有参数都需要计算梯度并由优化器更新
- 总计 (核心部分): (2 参数 + 2 梯度 + 8 优化器状态) * X GB = 12X GB
- 粗略预估下限: 14~18X GB
- 局部参数:
- LoRA 只训练一小部分注入到模型中的“适配器”参数,而原始模型的绝大部分参数保持冻结。
- 总显存 ≈ 2X GB + 激活值显存 + 几 GB 开销
估算:
- 全参数微调 (FP16, AdamW): 考虑 ~20X GB 或更多。
- LoRA 微调 (FP16): 考虑 ~(2.5 - 4)X GB,主要看基础模型 2X GB + 激活。
- QLoRA 微调 (4-bit base, LoRA): 考虑 ~(0.7 - 1.5)X GB,主要看基础模型 ~0.5X GB + 激活。
分析
- 关键变量: batch_size 和 sequence_length 对激活值影响巨大。如果显存不足,优先减小这两个值,或者加强梯度检查点的使用。
- 梯度检查点: 对于大模型微调(无论是全参数还是 LoRA),几乎是必需的技术,用计算换显存。
- 优化器: 如果显存极其紧张,可以考虑显存优化型的优化器(如 Adafactor, 8-bit Adam),但这可能会影响收敛效果。
- 分布式训练 (DeepSpeed ZeRO): 对于全参数微调或者超大模型的 LoRA 微调,单卡显存往往不够。DeepSpeed ZeRO (特别是 Stage 2 和 3) 可以将优化器状态和梯度分片到多张 GPU 上,极大降低单卡显存压力。
- 实际监控: 最好的方法是在目标硬件上用小 batch_size 跑一个测试批次,并使用 nvidia-smi 或 PyTorch 的 torch.cuda.memory_summary() / torch.cuda.max_memory_allocated() 来监控实际峰值显存占用,然后根据需要调整参数。
计算方法
LLM GPU显存计算公式为:
Memory
(GB) =P
x (Q
/8) × (1 + Overhead)
其中
- P: 参数数量(十亿)
- Q: 位精度(如FP16=16位),Q/8将位转换为字节
- Overhead: 额外开销(通常20%,包括KV缓存、激活缓冲区等)。
例如, 70B 模型使用FP16精度:
- 70×(16/8)×1.2 = 168GB。
这个公式可快速估算自托管LLM所需GPU显存,帮助选择合适的硬件配置。
Model Size(模型大小) | Precision(精度) | Overhead(开销) | Memory Required(所需内存) |
---|---|---|---|
7B | FP16 | 20% | 7×(16/8)×1.2 = 16.8 GB |
13B | FP16 | 20% | 13×(16/8)×1.2 = 31.2 GB |
70B | FP16 | 20% | 70×(16/8)×1.2 = 168 GB |
70B | INT8 | 20% | 70×(8/8)×1.2 = 84 GB |
175B | FP16 | 20% | 175×(16/8)×1.2 = 420 GB |
GPU 内存分配由多部分共同构成,核心组件及分配逻辑如下:
核心组成模块
- 模型权重(Model Weights):存储模型参数,对应占用 基础内存(Base Memory)。
- KV缓存(KV Cache Buffer):保存推理过程中的键值对中间数据,辅助序列生成等任务,产生 内存开销(Overhead)。
- 激活缓冲区(Activation Buffer):暂存计算过程中的激活值(如神经网络层输出),同样带来 内存开销(Overhead)。
总显存计算逻辑
总显存(Total VRAM)需整合各模块占用内存,公式可简化为:
Total VRAM = 模型权重内存 + KV缓存开销 + 激活缓冲区开销 + 其他潜在开销
GPU需为模型基础参数、推理中间数据、计算临时结果等分配内存,共同决定最终显存占用,理解此流程有助于优化AI任务的显存使用效率 。
推理显存
【2024-8-24】为大型语言模型 (LLM) 提供服务需要多少 GPU 内存?
运行一个大型语言模型,需要多大GPU内存?
GPU 内存估算公式
- $ M=(P4B)/(32/Q)1.2 $
解释
- M 代表 GPU 内存的大小,单位是吉字节。
- P 指的是模型中包含的参数总数。
- 4B 指的是每个参数平均占用的存储空间,为 4 个字节。
- Q 表示加载模型时使用的位数,可以是 16 位或者 32 位。
- 1.2 表示在计算中加入了 20% 的额外空间以应对可能的需求。
分解公式
- 模型参数量 (P):这个指标反映了你的模型规模。比如,如果你使用的是 LLaMA 模型,它包含 700 亿个参数,那么这个参数量就是 700 亿。
- 参数内存需求 (4B):通常情况下,每个模型参数需要 4 个字节的存储空间,这是因为浮点数通常需要 4 个字节(即 32 位)来表示。如果你采用的是半精度(16 位)格式,那么所需的内存量会相应减少。
- 参数位宽 (Q):这个值取决于你是以 16 位还是 32 位的精度来加载模型。16 位精度在许多大型语言模型的应用中较为普遍,因为它在保证足够精度的同时,能够降低内存的消耗。
- 额外开销 (1.2):乘以 1.2 的系数是为了增加 20% 的额外空间,以应对在模型推理过程中可能需要的额外内存。这不仅仅是为了安全起见,更是为了确保在模型执行过程中,激活操作和其他中间结果的内存需求得到满足。
- 其他难以估算和未知的显存消耗项在峰值时可能占总显存的30%以上
700亿个参数(以 16位精度加载)的 LLaMA 模型提供服务所需的内存:
- M = (P * 4B)/(32/Q) * 1.2 = (70 * 4 bytes)/(32/16) * 1.2 = 168 GB
- 单块 NVIDIA A100 GPU,尽管配备了 80 GB 显存,但仍然不足以支撑该模型的运行。为了高效地处理内存需求,至少需要两块 A100 GPU,每块都具备 80 GB 的显存容量。
关掉了梯度检查点,用 torch.bfloat16 类型的 Qwen-2.5-7B-instruction
在单卡H20上实验
- 当输入序列长度约400,batch size=4时,理论显存需要约110G,实际显存用了大概90G
- 进一步开启梯度检查点,下降到75G。
不同 zero策略下,分别需要几卡
- zero1: 优化器切分
- 当模型为7B时, k>2.29,约3卡;
- 当模型为14B时,任何非3D并行的zero1都无法有效训练,无论多少张A100。
- zero2: 进一步梯度切分
- 当模型为7B时,k>1.88,约需要2卡;
- 当模型为14B时, k>8.17 ,约需要9卡。
- 当模型超过20B,再多的A100也无法训练了。
- zero3: 进一步模型切分
- 当模型为7B时, k>1.7,约需要2卡;
- 当模型为14B时, k>4.31,约需要5卡。
- 训练上限为40B。
Deepspeed 不仅支持zero策略代表的dp,还支持tp和pp,因此,卡管够,理论上可以训无限大的模型,大力出奇迹。
LLaMA-6B 占用多大内存
【2023-7-13】LLaMA-6B 占用多大内存?计算过程
精度对所需内存的影响:
- fp32精度,一个参数需要 32 bits, 4 bytes.
- fp16精度,一个参数需要 16 bits, 2 bytes.
- int8精度,一个参数需要 8 bits, 1 byte.
模型需要的 RAM 大致分三个部分:
- 模型参数: 参数量*每个参数所需内存
- 对于
fp32
,LLaMA-6B需要 6B*4 bytes = 24GB 内存 - 对于
int8
,LLaMA-6B需要 6B*1 byte = 6GB 内存
- 对于
- 梯度: 参数量*每个梯度参数所需内存
- 优化器参数: 不同优化器所储存的参数量不同。
- 对于常用的
AdamW
,需要两倍模型参数(用来储存一阶和二阶momentum)。 fp32
的 LLaMA-6B,AdamW 需要 6B*8 bytes = 48 GBint8
的 LLaMA-6B,AdamW 需要 6B*2 bytes = 12 GB
- 对于常用的
- 其它
- CUDA kernel 也会占据一些RAM,大概 1.3GB 左右
综上,int8 精度的 LLaMA-6B 模型部分大致需要 6GB + 6GB + 12GB + 1.3GB = 25.3GB 左右。
再根据LLaMA的架构(hidden_size= 4096, intermediate_size= 11008, num_hidden_layers= 32, context_length = 2048)计算中间变量内存。每个instance需要: ( 4096+11008 ) * 2048 * 32 * 1 byte = 990 MB
所以,一张 A100(80GB RAM)大概可以在int8
精度,batch_size = 50
的设定下进行全参数训练。
附
- 消费级显卡内存和算力查询: 2023 GPU Benchmark and Graphics Card Comparison Chart
7B 占用多大内存
一个7B规模大模型(如LLaMA-2 7B),基于16-bit混合精度训练时
- 仅考虑模型参数、梯度、优化器情况下,显存占用就有112GB
- 参数占 GPU 显存近 14GB(每个参数2字节)。
- 训练时梯度存储占14GB(每个参数对应1个梯度,也是2字节)
- 优化器Optimizer(假设是主流的AdamW)则是84GB(每个参数对应1个参数copy、一个momentum和一个variance,这三个都是float32)
- 2byte 模型静态参数权重(以16bit存储) = 14G
- 2byte 模型更新参数权重 (以16bit存储)= 14G
- 2byte 梯度(以16bit存储)= 14G
- 2byte 梯度更新(以16bit存储)= 14G
- 4byte 一阶动量优化器更新(以32bit存储)= 28G
- 4byte 二阶方差优化器更新(以32bit存储)= 28G
- 目前,合计 112GB
- 还有:前向传播时激活值,各种临时变量
- 还与sequence length, hidden size、batch size都有关系。
目前A100、H100这样主流显卡单张是放不下,更别提国内中小厂喜欢用的A6000
/5000
、甚至消费级显卡。
PPO 显存预估
【2025-8-1】用 verl
进行 PPO 训练,4张80G显存的A800
能调起来14B模型?
rollout用vllm,训练用FSDP, 需要同时在显存中维护 3个14B规模的模型(Actor, Critic, Reference)以及 2份优化器状态
- 模型权重 (全部经过分片)
- Actor (14B, TP=4): ~7 G
- Critic (14B, FSDP): ~7 G
- Reference (14B, TP=4): ~7 G
- 小计: 21 G
优化器状态 (Actor 和 Critic, 经过分片)
- Actor 优化器: ~28 G
- Critic 优化器: ~28 G
- 小计: 56 G
梯度 (Actor 和 Critic, 经过分片)
- Actor 梯度: ~7 G
- Critic 梯度: ~7 G
- 小计: 14 G
静态占用总计: 21 GB (权重) + 56 GB (优化器) + 14 GB (梯度) = 91 G
这个估算出的 91 GB 静态占用已经超过了单张 80GB 卡的物理上限。
甚至还没有计算几十GB的激活值和 vLLM KV Cache 的空间!
显存不足怎么办
训练时显存不足怎么办?
常见的节省显存操作,优先级从高到低排列。
- 去掉 compute_metrics:
- 有些代码会在输出层后计算rouge分等,这个会输出一个
batch_size
vocab_size
seq_len
的一个大向量,非常占显存。
- 有些代码会在输出层后计算rouge分等,这个会输出一个
- 采用
bf16
/fp16
进行混合精度训练:- 现在大模型基本上都采用 bf16 来进行训练
- 但是 v100 不支持 bf16,可以采用fp16进行训练。显存占用能够降低1倍。
Flash attention
:不仅能够降低显存,更能提高训练速度。batch_size
调小:- batch size 与模型每层激活状态所占显存呈正相关
- 降低 batch size 能够很大程度上降低这部分显存占用。
- 采用梯度累积:
global_batch_size
=batch_size
*梯度累积
- 如果降低 batch_size 后想保持 global_batch_size 不变,可适当提高梯度累积值。
- 选择合适的上下文长度:
- 上下文长度与激活状态所占显存呈正相关
- 因此可适当降低上下文长度来降低显存占用。
DeepSpeed Zero
:- 显存占用从高到低为:
Zero 1
>Zero 2
>Zero 2
+offload
>zero 3
>zero 3
+offload
- 推荐最多试到
Zero2
+offload
。
- 显存占用从高到低为:
- 选择更小的基座模型:在满足需求的情况下,尽量选择更小的基座模型。
慎重选择:
Lora
: 能跑全参就别跑Lora
或Qlora
,一方面是麻烦,另一方面的确是效果差点。Qlora
: Qlora 速度比lora慢,但所需显存更少,实在没资源可以试试。Megatron-LM
: 可采用流水线并行和张量并行,使用比较麻烦,适合喜欢折腾的同学。Pai-Megatron-LM
: Megatron-LM 的衍生,支持 Qwen 的sft和pt,坑比较多,爱折腾可以试试。- 激活检查点:不推荐,非常耗时。在反向传播时重新计算深度神经网络的中间值。用时间(重新计算这些值两次的时间成本)来换空间(提前存储这些值的内存成本)。
Adam + fp16 混合精度预估
【2023-6-29】LLM Training GPU显存耗用量估计,以Adam + fp16混合精度训练为例,分析其显存占用有以下四个部分
- (1) 模型权重 Model
- Prameters (FP16) 2 bytes
- Gradients (FP16) 2 bytes
- (2) 前向激活值 Activations
- 前向过程中存储, y = w1 * x, 存储x用于计算w1梯度
- 整体显存占用与batch有关
- (3) 优化器 Optimizer:梯度、动量等
- Master Weight (FP32) 4 bytes
- Adam m (FP32) 4 bytes
- Adam v (FP32) 4 bytes
- (4) 临时混存 Buffer & Fragmentation
(1) 和 (3) 可以精确估计
- 显存占用大头是 Adam 优化器,占可计算部分的 12/16=75%
- 其次是模型参数+梯度,显存容量至少是参数量的16倍
Adam + fp16混合精度训练
结论:
- 不考虑Activation,3090 模型容量上限是 24/16=1.5B,A100 模型容量上限是 80/16=5B
- 假设训练过程中batchsize恒定为1,也即尽最大可能减少Activation在显存中的占用比例,使得理论计算值16Φ更接近真实的显存占用,那么24G的3090的模型容量上限是1.5B(差不多是GPT-2的水平),80G的A100的模型容量上限是5B
- 考虑Activation,3090的模型容量上限是 0.75B,A100的容量上限是 2.5B
- batchsize为1的训练效率非常低,batchsize大于1才能充分发挥GPU的效率,此时Activation变得不可忽略。经验之谈,一般需要给Activation预留一半的显存空间(比如3090预留12G,A100预留40G),此时3090的模型容量上限是0.75B,A100的容量上限是2.5B,我们实际测试结果接近这个值
- [1B, 5B] 是目前市面上大多数GPU卡的分水岭区间
- [0, 1B) 市面上绝大多数卡都可以直接硬train一发
- [1B, 5B] 大多数卡在这个区间的某个值上触发模型容量上限,具体触发值和显存大小有关
- (5B, ~) 目前没有卡能裸训
节省显存
深度学习中,一般占用显存最多的是卷积等层的输出,模型参数占用的显存相对较少,而且不太好优化。
节省显存方法:
- 降低 batch-size
- 下采样 (NCHW -> (1/4)*NCHW)
- 减少全连接层(一般只留最后一层分类用的全连接层
更多信息见原文
DeepSpeed ZeRO 操作就优化梯度优化器里面的参数,达到缩减显存占用空间的操作。