#最佳实践 显存占用 85% 算是榨干
通俗来说:
- **GPU 的显存(VRAM)**,类似于电脑的内存(RAM),但它是显卡上的专用内存,专门给**GPU**使用。
- CPU 的内存(RAM)用于处理一般数据和代码执行。
- **GPU 显存**则用于专门存放 GPU 运算需要的数据,比如模型参数、数据输入、输出结果、梯度信息等。
---
## 📌 为什么训练模型时显存经常不够用?
因为模型训练时需要把以下内容全部装进 GPU 显存中:
- **模型本身的参数**:模型越大,占用显存越多。
- **输入的数据**(如token化后的文本数据)。
- **中间结果与梯度信息**(用于反向传播和更新参数的计算)。
- **优化器信息**(如 Adam 优化器会额外存储一部分数据)。
当你的任务特别大(比如大模型、大批次数据)或打开了额外的优化选项(如 Liger、FlashAttention 等),都会导致 GPU 显存需求大幅增加,可能会超出 GPU 提供的显存容量,引发显存不足。
---
## 🚩 举个简单例子
|项目|占用的 GPU 显存(示例)|
|---|---|
|模型参数(Qwen 1.5B)|大约 3~5GB 左右|
|数据输入 (Batch)|大约 2~4GB 左右|
|梯度计算、中间结果|大约 4~8GB 左右|
|优化器状态|大约 2~4GB 左右|
|Liger 优化|额外的显存开销(1~3GB以上)|
当这些数据全部加载后,你的 GPU 显存(24GB)可能就不够用了。
---
## 🚩 因此
- 如果出现显存不足,就应当适当关闭一些占用显存的优化(如`use_liger`)。
- 或者减小单次训练的数据量(如减小 batch size)。
现在关闭`use_liger`即可有效降低显存占用。
调整 `per_device_train_batch_size`(单GPU训练时每个GPU上训练的批次大小)的核心目的是:
> 在充分利用GPU显存且避免显存溢出的前提下,**最大化批次大小以提升训练吞吐量**。
---
## 🚩 如何确定最佳 `per_device_train_batch_size`?
可以通过以下具体方法进行判断:
### 🔹 方法一:逐步尝试法(最常用、最简单)
逐渐增加批次大小(如 2→4→8→16),观察训练时GPU显存占用情况:
- 当显存稳定且利用率较高(80%~90%以上),且没有出现OOM(显存溢出)时,批次大小就是合适的。
- 若出现OOM错误,则往下降一个档次。
例如,推荐的步骤:
```bash
--per_device_train_batch_size 2 (目前情况) ✅
--per_device_train_batch_size 4 (测试,如无OOM,继续尝试更大)
--per_device_train_batch_size 8 (测试,如出现OOM,回退到4)
```
---
### 🔹 方法二:显存计算经验法(快速估算)
可根据模型大小和序列长度进行粗略推算:
经验公式(以Qwen1.5B模型、4096序列长度、fp16为例):
- fp16模式下,每个参数约占用2字节。
- 每个样本内存需求约估算为:
- **参数内存**:1.5B × 2 bytes = 3GB(约等于模型参数存储)
- **激活值内存**:显存占用主要由激活值决定,通常可达模型参数大小的数倍。
通常**Qwen类模型**经验估计激活内存为:
`参数内存 × 序列长度 ÷ 1000` 左右。
- 举例:
```Java
参数内存 = 3GB
激活内存 ≈ 3GB × 4096 / 1000 ≈ 12.3GB
单个样本内存占用 ≈ 3GB (参数) + 12.3GB (激活) ≈ 15GB
```
- 你的GPU是96GB,可推算最多大概容纳:
`96GB ÷ 15GB ≈ 6个样本`
考虑训练时还要预留一些缓存空间,保守建议:
- **批次大小设置为4-6比较合适**。
---
### 🔹 方法三:观察GPU状态动态监控法(推荐方式)
训练时,实时监控GPU显存状态:
```bash
watch -n 1 nvidia-smi
```
理想的显存利用率范围:
- **显存使用率:85%~95%** 是最佳范围。
- 若低于70%,则表示显存利用不足,可以进一步增加批次大小。
- 若长期保持99%-100%,风险较大,可能随时OOM,应降低批次大小。
---
## 🚩 综合推荐批次大小(针对你的配置)
你目前的配置:
- GPU: H20-NVLink (96GB) 单卡
- 模型: Qwen2.5-1.5B (参数量适中)
- 序列长度: 4096
- 精度模式: fp16(节省显存)
考虑以上因素:
|现有批次大小|推荐批次大小|原因|预估显存占用率|
|---|---|---|---|
|2|**4~6**|较充分利用显存,效率更高|80% ~ 90% 左右|
你可以直接尝试:
```bash
--per_device_train_batch_size 4
```
- 如果训练顺利,显存利用合理 (~80%-90%),则可进一步尝试 `batch_size=6`。
- 如果4就OOM,则维持批次大小4即可。
---
## 🚩 调整后预期效果
- 若批次大小从2调高至4,训练速度预计提升近乎2倍(训练时间缩短约一半)。
- 若能调高至6,则速度提升更多。
举例:
|批次大小|每秒迭代次数|总耗时 (训练约68530步)|
|---|---|---|
|2(当前)|1.2 it/s|~15小时|
|4(预计)|2.4 it/s左右|~7.5小时(缩短一半)|
|6(预计)|3.6 it/s左右|~5小时内(大幅提速)|
---
## 🚩 总结(最佳实践)
- 首先尝试 `per_device_train_batch_size=4`:
- 观察显存占用率,若有余量再适当提高。
- 通过`nvidia-smi`监控显存,确保稳定运行且高效。
这种方式简单可靠,是确定最佳批次大小的最推荐方式。