Pytorch显存管理
Pytorch显存
显存分配机制
torch.cuda.memory_allocated() # torch.tensor占用的显存
torch.cuda.max_memory_allocated() # 全部占据的缓存有多少,效果与memory_reserved一样
torch.cuda.memory_reserved() # 查看当前进程分配的显存缓冲区是多少
torch.cuda.empty_cache() # 将未占用的缓存收回
torch.cuda.memory_summary() # 显示显存信息
PyTorch context: 第一次执行CUDA操作,也就是使用GPU的时候所需要创建的维护设备间工作的一些相关信息。只要你把任何东西(无论是多小的tensor)放到GPU显存中,那么你至少会占用1000MiB左右的显存(根据cuda版本,会略有不同)。这部分显存是cuda running时固有配件必须要占掉的显存,是无法避免的,这就是pytorch的context开销。
总显存:Reserved_memory
+ Pytorch context
Reserved_memory
:剩余的缓存 + 变量Allocated memory
在 Pytorch 中,显存分配应该是按页分配,即使是很小的tensor,分配的显存也是以页为单位的。CUDA 内存以内存块的形式存在,在你创建一条 4 Bytes 的 Tensor 时,默认情况下,Pytorch 会向 CUDA 申请 2 MB 的内存块,然后再为我们分配 512 Bytes 的显存来储存我们申请的 Tensor。剩余的 1.5 MB 以 reserved memory(以前叫 cache memory)的形式保持占用。假设这时候,你想再申请一条 Tensor,Pytorch 首先会去看之前申请的内存块够不够放。如果我们申请的 Tensor 小于 1.5MB,那就直接放在刚刚申请的内存块中。如果大于 1.5MB,Pytorch 则再向 CUDA 申请新的内存块。假设 CUDA 也没有足够内存的时候,Pytorch 会尝试切分释放掉这些内存块中闲置的部分,再重新向 CUDA 申请。如果还不够,那就会报我们模型训练中常见的 out of memory 错误了。
刚刚讲的是小于 1 MB 的显存申请,大于 1 MB 小于 10MB 的申请,在没有足够空闲内存块的情况下,则会向 CUDA 申请 20 MB 的内存块。
模型显存分配
PyTorch在进行深度学习训练的时候,有4大部分的显存开销,分别是模型参数(parameters),模型参数的梯度(gradients),优化器状态(optimizer states)以及中间激活值(intermediate activations) 或者叫中间结果(intermediate results)。
1.模型定义:定义了模型的网络结构,产生模型参数;
while(你想训练):
2.前向传播:执行模型的前向传播,产生中间激活值;
3.后向传播:执行模型的后向传播,产生梯度;
4.梯度更新:执行模型参数的更新,第一次执行的时候产生优化器状态。
模型定义:显存占用量约为参数量乘以4
前向传播:显存增加等于每一层模型产生的结果的显存之和,且跟batch_size成正比。
后向传播:后向传播会将模型的中间激活值给消耗并释放掉掉,并为每一个模型中的参数计算其对应的梯度。在第一次执行的时候,会为模型参数分配对应的用来存储梯度的空间。
参数更新:第一次增加,以后不再额外分配显存
其中中间结果显存占50%以上
GPU中显存优化:
- 数据:采用更小的精度
- 模型:得到的中间结果、loss 等不在显存中把保存;
total_loss += loss.item()
- 中间结果(forward):训练结束后将cuda上的变量删除
- 梯度信息:测试时使用
torch.no_grad()
不保留梯度信息