深度学习模型以及中间变量的显存占用大小分析

本文详细解析了深度学习过程中显存占用的原因,并介绍了如何计算显存使用量的方法。此外,还探讨了各种因素对显存的影响及优化策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

亲,显存炸了,你的显卡快冒烟了!

torch.FatalError: cuda runtime error (2) : out of memory at /opt/conda/conda-bld/pytorch_1524590031827/work/aten/src/THC/generic/THCStorage.cu:58

想必这是所有炼丹师们最不想看到的错误,没有之一。

OUT OF MEMORY,显然是显存装不下你那么多的模型权重还有中间变量,然后程序奔溃了。怎么办,其实办法有很多,及时清空中间变量,优化代码,减少batch,等等等等,都能够减少显存溢出的风险。

但是这篇要说的是上面这一切优化操作的基础,如何去计算我们所使用的显存。学会如何计算出来我们设计的模型以及中间变量所占显存的大小,想必知道了这一点,我们对自己显存也就会得心应手了。

如何计算

首先我们应该了解一下基本的数据量信息:

  • 1 G = 1000 MB
  • 1 M = 1000 KB
  • 1 K = 1000 Byte
  • 1 B = 8 bit

好,肯定有人会问为什么是1000而不是1024,这里不过多讨论,只能说两种说法都是正确的,只是应用场景略有不同。这里统一按照上面的标准进行计算。

然后我们说一下我们平常使用的向量所占的空间大小,以Pytorch官方的数据格式为例(所有的深度学习框架数据格式都遵循同一个标准):

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

我们只需要看左边的信息,在平常的训练中,我们经常使用的一般是这两种类型:

  • float32 单精度浮点型
  • int32 整型

一般一个8-bit的整型变量所占的空间为1B也就是8bit。而32位的float则占4B也就是32bit。而双精度浮点型double和长整型long在平常的训练中我们一般不会使用。

ps:消费级显卡对单精度计算有优化,服务器级别显卡对双精度计算有优化。

也就是说,假设有一幅RGB三通道真彩色图片,长宽分别为500 x 500,数据类型为单精度浮点型,那么这张图所占的显存的大小为:500 x 500 x 3 x 4B = 3M。

而一个(256,3,100,100)-(N,C,H,W)的FloatTensor所占的空间为256 x 3 x 100 x 100 x 4B = 31M

不多是吧,没关系,好戏才刚刚开始。

显存去哪儿了

看起来一张图片(3x256x256)和卷积层(256x100x100)所占的空间并不大,那为什么我们的显存依旧还是用的比较多,原因很简单,占用显存比较多空间的并不是我们输入图像,而是神经网络中的中间变量以及使用optimizer算法时产生的巨量的中间参数。

我们首先来简单计算一下Vgg16这个net需要占用的显存:

通常一个模型占用的显存也就是两部分:

  • 模型自身的参数(params)
  • 模型计算产生的中间变量(memory)

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

图片来自cs231n,这是一个典型的sequential-net,自上而下很顺畅,我们可以看到我们输入的是一张224x224x3的三通道图像,可以看到一张图像只占用150x4k,但上面标注的是150k,这是因为上图中在计算的时候默认的数据格式是8-bit而不是32-bit,所以最后的结果要乘上一个4。

我们可以看到,左边的memory值代表:图像输入进去,图片以及所产生的中间卷积层所占的空间。我们都知道,这些形形色色的深层卷积层也就是深度神经网络进行“思考”的过程:

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

图片从3通道变为64 –> 128 –> 256 –> 512 …. 这些都是卷积层,而我们的显存也主要是他们占用了。

还有上面右边的params,这些是神经网络的权重大小,可以看到第一层卷积是3×3,而输入图像的通道是3,输出通道是64,所以很显然,第一个卷积层权重所占的空间是 (3 x 3 x 3) x 64。

另外还有一个需要注意的是中间变量在backward的时候会翻倍!

为什么,举个例子,下面是一个计算图,输入x,经过中间结果z,然后得到最终变量L

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

我们在backward的时候需要保存下来的中间值。输出是L,然后输入x,我们在backward的时候要求Lx的梯度,这个时候就需要在计算链Lx中间的z

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

dz/dx这个中间值当然要保留下来以用于计算,所以粗略估计,backward的时候中间变量的占用了是forward的两倍!

优化器和动量

要注意,优化器也会占用我们的显存!

为什么,看这个式子:

《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》

上式是典型的SGD随机下降法的总体公式,权重W在进行更新的时候,会产生保存中间变量《浅谈深度学习:如何计算模型以及中间变量的显存占用大小》,也就是在优化的时候,模型中的params参数所占用的显存量会翻倍。

当然这只是SGD优化器,其他复杂的优化器如果在计算时需要的中间变量多的时候,就会占用更多的内存。

模型中哪些层会占用显存

有参数的层即会占用显存的层。我们一般的卷积层都会占用显存,而我们经常使用的激活层Relu没有参数就不会占用了。

占用显存的层一般是:

  • 卷积层,通常的conv2d
  • 全连接层,也就是Linear层
  • BatchNorm层
  • Embedding层

而不占用显存的则是:

  • 刚才说到的激活层Relu等
  • 池化层
  • Dropout层

具体计算方式:

  • Conv2d(Cin, Cout, K): 参数数目:Cin × Cout × K × K
  • Linear(M->N): 参数数目:M×N
  • BatchNorm(N): 参数数目: 2N
  • Embedding(N,W): 参数数目: N × W

额外的显存

总结一下,我们在总体的训练中,占用显存大概分以下几类:

  • 模型中的参数(卷积层或其他有参数的层)
  • 模型在计算时产生的中间参数(也就是输入图像在计算时每一层产生的输入和输出)
  • backward的时候产生的额外的中间参数
  • 优化器在优化时产生的额外的模型参数

但其实,我们占用的显存空间为什么比我们理论计算的还要大,原因大概是因为深度学习框架一些额外的开销吧,不过如果通过上面公式,理论计算出来的显存和实际不会差太多的。

如何优化

优化除了算法层的优化,最基本的优化无非也就一下几点:

  • 减少输入图像的尺寸
  • 减少batch,减少每次的输入图像数量
  • 多使用下采样,池化层
  • 一些神经网络层可以进行小优化,利用relu层中设置inplace
  • 购买显存更大的显卡
  • 从深度学习框架上面进行优化

下篇文章我会说明如何在Pytorch这个深度学习框架中跟踪显存的使用量,然后针对Pytorch这个框架进行有目的显存优化。

参考:
https://blog.youkuaiyun.com/liusandian/article/details/79069926

<think>好的,我现在需要解决用户在Jupyter Notebook中运行深度学习模型时GPU占用率为0的问题。首先,我需要回顾用户提供的引用内容,看看是否有相关的解决方案。 用户提到的引用[1]提到了elastic-jupyter-operator,这个工具主要是用来优化GPU资源利用的,可能和自动回收空闲资源有关,但用户当前的问题是GPU没有被使用,而不是资源回收的问题。引用[2]提到用户自己搭建了一个CNN模型,但因为没有GPU所以在CPU上训练,这可能说明用户的环境可能存在配置问题,或者代码中没有正确指定使用GPU。引用[3]介绍了CUDA,这可能涉及到驱动和环境的检查。引用[4]和[5]主要关于大语言模型训练和预训练模型的选择,可能与当前问题关联不大。 接下来,我需要考虑可能导致GPU占用率为0的原因。首先,检查CUDAPyTorch/TensorFlow是否正确安装,并且版本是否兼容。如果安装不正确,框架可能无法检测到GPU,从而回退到CPU。其次,代码中是否显式地将模型和数据移动到GPU上,例如使用`.to('cuda')`或`.cuda()`。另外,需要确认是否有权限问题,或者GPU是否被其他进程占用,导致无法使用。此外,Jupyter Notebook本身可能在某些配置下无法正确访问GPU资源,可能需要检查内核配置或重启服务。 然后,根据常见的解决方案,分步骤排查。首先检查CUDA是否可用,例如在PyTorch中运行`torch.cuda.is_available()`,如果返回False,则需要检查驱动和CUDA安装。接着,确保代码中正确调用了GPU,例如模型和数据都转移到GPU,并且计算过程中没有意外地转回CPU。此外,监控GPU使用情况可以使用`nvidia-smi`命令,观察是否有进程占用GPU。如果所有步骤都正确,可能需要考虑Jupyter的环境变量或内核配置是否有问题,比如是否在正确的虚拟环境中安装了GPU版本的框架。 最后,结合用户提供的引用内容,引用[3]关于CUDA的说明可能相关,需要用户确认CUDA环境正确配置。引用[2]提到用户没有GPU,但当前问题用户是有GPU而未被使用,所以可能用户的环境配置存在问题。需要用户按照步骤检查驱动、CUDA、框架版本,并确保代码正确使用GPU。如果问题仍然存在,可能需要更深入的系统诊断,或者考虑使用类似引用[1]中的工具来管理GPU资源,但主要问题可能还是配置或代码问题。</think>### Jupyter Notebook深度学习模型GPU占用率0的解决方案 #### 1. 验证GPU驱动与CUDA环境 首先确认系统已正确安装GPU驱动和CUDA工具包。在终端执行以下命令: ```bash nvidia-smi # 查看GPU状态 nvcc --version # 查看CUDA版本 ``` 如果`nvidia-smi`显示GPU信息但`nvcc`报错,说明CUDA未正确安装[^3]。 #### 2. 检查深度学习框架的GPU支持 在Jupyter Notebook中验证框架是否识别到GPU: ```python # PyTorch验证 import torch print(torch.cuda.is_available()) # 应输出True print(torch.cuda.current_device()) # 应显示GPU编号 # TensorFlow验证 import tensorflow as tf print(tf.config.list_physical_devices('GPU')) # 应显示GPU设备列表 ``` 若输出异常,需重新安装对应框架的GPU版本: ```bash # PyTorch安装命令示例 pip install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117 ``` #### 3. 代码层强制指定GPU 在模型和数据操作中显式指定设备: ```python device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # 模型转移 model = YourModel().to(device) # 数据转移 inputs = data.to(device) ``` 特别注意:损失函数计算结果需保留在GPU,避免中间结果回传至CPU[^2]。 #### 4. 监控GPU使用状态 在训练过程中保持终端监控: ```bash watch -n 0.1 nvidia-smi # 每0.1秒刷新GPU状态 ``` 正常训练时应看到显存占用和计算利用率波动。若仍为0%,可能是: - 批量大小过小(建议≥32) - 模型复杂度不足(可增加层数/通道数测试) - 数据预处理存在CPU阻塞 #### 5. 排查Jupyter环境配置 当使用Kubernetes部署时,确认: ```yaml # 部署配置需包含GPU声明 resources: limits: nvidia.com/gpu: 1 ``` 建议尝试使用`elastic-jupyter-operator`进行动态资源管理,避免资源分配冲突[^1]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值