Python tensorflow报错: CUDA_ERROR_OUT_OF_MEMORY

tensorflow报错: CUDA_ERROR_OUT_OF_MEMORY

这几天在做卷积神经网络的一个项目,遇到了一个问题CUDA_ERROR_OUT_OF_MEMORY。运行代码时前三四百次都运行正常,之后就一直报这个错误(而且第二次、第三次重新运行程序时,报错会提前),但是程序不停止。今天空闲下来,就看一看 这个问题。
详细信息(因为我的报错解决了,所以从网上找了一个相同的报错信息):

2017-03-28 23:38:19.485396: E tensorflow/stream_executor/cuda/cuda_driver.cc:924] failed to alloc 8589934592 bytes on host: CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.485583: W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195] could not allocate pinned host memory of size: 8589934592
2017-03-28 23:38:19.485729: E tensorflow/stream_executor/cuda/cuda_driver.cc:924] failed to alloc 7730940928 bytes on host: CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.485823: W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195] could not allocate pinned host memory of size: 7730940928
2017-03-28 23:38:19.485932: E tensorflow/stream_executor/cuda/cuda_driver.cc:924] failed to alloc 6957846528 bytes on host: CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486023: W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195] could not allocate pinned host memory of size: 6957846528
2017-03-28 23:38:19.486165: E tensorflow/stream_executor/cuda/cuda_driver.cc:924] failed to alloc 6262061568 bytes on host: CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486233: W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195] could not allocate pinned host memory of size: 6262061568
2017-03-28 23:38:19.486324: E tensorflow/stream_executor/cuda/cuda_driver.cc:924] failed to alloc 5635855360 bytes on host: CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486390: W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195] could not allocate pinned host memory of size: 5635855360

谷歌翻译一下

2017-03-28 23:38:19.485396:E tensorflow / stream_executor / cuda / cuda_driver.cc:924]无法在主机上分配8589934592字节:CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.485583:W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195]无法分配大小为8589934592的固定主机内存
2017-03-28 23:38:19.485729:E tensorflow / stream_executor / cuda / cuda_driver.cc:924]无法在主机上分配7730940928字节:CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.485823:W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195]无法分配大小为7730940928的固定主机内存
2017-03-28 23:38:19.485932:E tensorflow / stream_executor / cuda / cuda_driver.cc:924]无法在主机上分配6957846528字节:CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486023:W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195]无法分配大小为6957846528的固定主机内存
2017年3月28日23:38:19.486165:E tensorflow / stream_executor / cuda / cuda_driver.cc:924]无法在主机上分配6262061568字节:CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486233:W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195]无法分配大小为6262061568的固定主机内存
2017-03-28 23:38:19.486324:E tensorflow / stream_executor / cuda / cuda_driver.cc:924]无法在主机上分配5635855360字节:CUDA_ERROR_OUT_OF_MEMORY
2017-03-28 23:38:19.486390:W ./tensorflow/core/common_runtime/gpu/pool_allocator.h:195]无法分配大小为5635855360的固定主机内存

GPU显存不足

百度了一下这个问题,出现的都是说GPU显存不足,解决方法也很简单。

一、硬件上,直接换机器,增加显存

二、软件上,修改代码

1.通过代码指定GPU显存的最大占有率,同时指定一块GPU(有时候GPU指定错误也会发生这种情况)

import tensorflow as tf
import os
os.environ["CUDA_VISIBLE_DEVICES"] = '0'   #指定0号GPU可用
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.5  # 程序最多只能占用指定gpu50%的显存
config.gpu_options.allow_growth = True      #程序按需申请内存
sess = tf.Session(config = config)

2.修改程序,减小显存需求
显存主要用于模型的参数、优化器的参数、输入输出。

模型的参数主要是网络层的Weight和Bias。

优化器参数指的是模型在反向传播过程中产生的参数,这部分参数主要是梯度。在SGD中,其大小与参数一样,因此模型的参数所占用的显存会翻倍。在Adam中,模型的参数量会翻4倍。

显存占用 = 模型显存占用 + batch_size × 每个样本的显存占用

通常如果模型的的参数按照float32(4个Byte)保存,那么显存的占用=参数量*4,但是实际需要的显存因为还有其它开销,所以比上述这种方式计算得到的值还要再大一些。

(1)降低batch-size(batch-size和显存的占用不成正比)
(2)采样(NCHW -> (1/4)*NCHW)
(3)减少全连接层(一般只留最后一层分类用的全连接层)
(4)减小参数大小,缩减图片尺寸(这样会大幅降低显存需求,但会减缓训练速度,降低网络质量)
3.多GPU训练的时候,中心GPU显存不足
在数据并行的训练过程中,有时候会发生0号卡的显存占用明显多于其余卡。原因如下:
DataParallelTable内部会有一个中心结点,来调度其他 GPU 的数据和模型。因此,即使每个 GPU 平均分配同样的 batch 大小,第一个 GPU 占用的显存还是会比其他 GPU 多。而且,并行的 GPU 越多,占用的显存越多。举个例子,当我使用8张卡来训练时,开的 batch 大小为32,这样DataParallelTable内部会平均分配,每个 GPU 运行的 batch 为4。正常来说,单卡运行 4 batch 是11G的显存,刚好把卡占满。然而,由于中心结点会占用更多,所以程序会报显存不足的错。
如果减少 batch 为30,DataParallelTable会分配6张卡(包括中心结点)运行4个,剩下两张卡运行3个 batch,还是显存不足,直到中心结点运行3个 batch。但这样,总的 batch 就只能是24,除了中心结点,其余的卡的内存都不能占满,造成了浪费。
可以通过修改cunn的源码,自己配置 batch 的分配方式,解决这个问题。
4.GPU显存占用为0,但仍然有显存不足报错
因为系统和运行环境的原因,GPU的序号和我们想的会有出入。用一下代码查看GPU序号,设定正确的GPU。

from tensorflow.python.client import device_lib
# 列出所有的本地机器设备
local_device_protos = device_lib.list_local_devices()
# 打印
# print(local_device_protos)
# 只打印GPU设备
[print(x) for x in local_device_protos if x.device_type == 'GPU']

若显示无GPU设备,则检查环境安装是否正确,如GPU驱动、CUDA、cudnn、tensorflow-gpu、python,以及它们的版本关系。

电脑内存不足

以上答案并没有解决我的问题,我又找了一些资料,发现可能是内存不足的问题。

Host means CPU. The error comes from a CUDA API which allocates physical CPU memory and pins it so that the GPU can use it for DMA transfers to and from the GPU and CPU. You are running out of CPU memory.
How are you feeding data to the model? Memory usage often gets out of control if training data is embedded in the graph (e.g. with a tf.constant), in which case switching over to a feed_dict or queue-based input would keep memory usage constant across steps.

这两段话说明了failed to alloc 8589934592 bytes on host是因为主机内存不足。原因是如果将训练数据嵌入到计算图中(例如使用tf.constant),则内存使用率通常会失控,在这种情况下,切换到基于feed_dict或基于队列的输入将使内存使用率在各个步骤之间保持恒定。
解决方法:

一、硬件上,更换机器,增加内存。

二、软件上,修改代码

1、修改程序源代码,减少tf.constant的使用,改用feed_dict给使用。
placeholder创建出来的tensor赋值,feed_dict 只在调用它的方法内有效, 方法结束, feed_dict 就会消失,所以不会爆内存。
2、修改CUDA源码,改变内存的申请和使用方式,及时释放内存。
建议针对cudaMemcpy()调用中的源内存或者目标内存,才使用页锁定内存,并且在不在使用他们的时候立即释放。

我的解决方法:

我的原代码是用tf.train.string_input_producer()的文件读取机制,利用多线程
读取,读取线程源源不断地将文件系统中的图片读入到一个内存的队列中,而负责计算的是另一个线程,计算需要数据时,直接从内存队列中取就可以了。这样就可以解决GPU因为IO而空闲的问题!但问题是,图像存在内存队列中会导致内存不足而报错。给个数据我的设备是16G内存,跑的项目是5100张480*640的jpg格式图片,就报错了。
我改成每次迭代从硬盘读取几张图片到内存,手写了一个I/O读取函数,就没有报错了。缺点是迭代速度大幅减小,这样做有好处也有坏处,看各位的取舍。

CUDA占电脑内存的原因:

malloc()分配的标准的,可分页的主机内存(即固定内存和虚拟内存),而cudaHostAlloc()分配的是页锁定的主机内存,也称作固定内存pinned memory,或者不可分页内存,它的一个重要特点是操作系统将不会对这块内存分页交换到磁盘上,从而保证了内存始终驻留在物理内存中。当时使用固定内存时,虚拟内存的功能就会失去,尤其是在应用程序中使用每个页锁定内存时都需要分配物理内存,而且这些内存不能交换到磁盘上。这将会导致系统内存会很快地被耗尽,因此应用程序在物理内存较少的机器上会运行失败。

详细原因可以查看这篇博客:6.1 CUDA: pinned memory固定存储

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值