如何解决 TensorFlow 中的“gpu 内存不足”问题
Posted
技术标签:
【中文标题】如何解决 TensorFlow 中的“gpu 内存不足”问题【英文标题】:How can I solve 'ran out of gpu memory' in TensorFlow 【发布时间】:2016-08-23 23:33:24 【问题描述】:我在 TensorFlow 中使用 2 个卷积层和一个全连接层运行 MNIST 演示,我收到一条消息“内存不足,试图分配 2.59GiB”,但它显示总内存为 4.69GiB,并且是空闲的内存是3.22GiB,怎么能停在2.59GiB?并且对于更大的网络,我如何管理 gpu 内存?我只关心如何充分利用 gpu 内存并想知道它是如何发生的,而不是如何预先分配内存
【问题讨论】:
How to prevent tensorflow from allocating the totality of a GPU memory?的可能重复 之前见过,不过是指预分配gpu内存,不是内存不足 【参考方案1】:在 GTX 970 上训练小型 CNN 时,我遇到了内存不足的错误。由于某种侥幸,我发现告诉 TensorFlow 根据需要(而不是预先)在 GPU 上分配内存解决了我的所有问题。这可以使用以下 Python 代码来完成:
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
以前,TensorFlow 会预先分配约 90% 的 GPU 内存。出于某种未知原因,即使模型可以完全适合 GPU 内存,这也会导致内存不足错误。通过使用上面的代码,我不再有OOM错误。
注意:如果模型太大而无法放入 GPU 内存,这可能无济于事!
【讨论】:
这对我来说也适用于 keras 和 conda 安装。 在我的辩护中,这个问题没有引用或标记 Keras。 @nickandross “出于某种未知原因...”我只是想补充一点,原因是为了避免从主 RAM 到 GPU 内存的不必要/额外数据传输,因为数据传输比计算本身并可能成为瓶颈。因此,它可以节省时间先传输尽可能多的数据,而不是分配一点点,计算一些(快速),等待更多数据传输(相对较慢),然后快速计算,而不是再次等待更多数据到达 GPU 等... @Schütze 请参阅下面的答案 - 也许您的问题是您使用的是 Tensorflow 2? @ElegantCode 只是为了记录,“出于某种未知原因......”是指句子的第二部分(内存不足),而不是前一句(谈论预分配) .【参考方案2】:不是这样的。首先,您可以通过监控您的 gpu 来查看它在运行时获得了多少内存。例如,如果您有一个 nvidia gpu,您可以使用watch -n 1 nvidia-smi
命令进行检查。
但在大多数情况下,如果您没有设置 gpu 内存的最大比例,它几乎会分配整个空闲内存。您的问题是您的 gpu 内存不足。 cnn 网络非常繁重。当您尝试为您的网络提供数据时,请勿使用您的全部数据。以小批量执行此进料程序。
【讨论】:
我有一个相当大的网络(CNN+LSTM)。我的输入数据大小为 batch_size = 5, (5x396x396)——它是一个 3D 体积。所以一个相当小的批量大小。我在具有 8GB RAM 的 GTX 1070 上运行,但内存仍然不足。你知道有什么解决方法吗?任何概述解决方法的教程? 那我如何通过小批量?我使用train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(batch_size=batch_size)
,然后以for x_batch, y_batch in train_dataset.prefetch(tf.data.experimental.AUTOTUNE).cache():
进行迭代,但内存不足。有任何想法吗?我不想发布具有相同标题的问题,但这里没有对我有用的回复。
不要使用cache()
。当您使用此命令时,之前的所有内容都会保存在内存中。对于这样的数据集,请避免缓存。它可以显着提高速度,但前提是您可以使用更大的 RAM。【参考方案3】:
默认情况下,TensorFlow 将几乎所有 GPU 的所有 GPU 内存(受 CUDA_VISIBLE_DEVICES 限制)映射到进程可见。这样做是为了通过减少内存碎片来更有效地使用设备上相对宝贵的 GPU 内存资源。
TensorFlow 在 Session 上提供了两个 Config 选项来控制它。
第一个是 allow_growth 选项,它尝试根据运行时分配只分配尽可能多的 GPU 内存:
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)
第二种方法是 per_process_gpu_memory_fraction 选项,它决定了每个可见 GPU 应该分配的内存总量的比例。例如,您可以通过以下方式告诉 TensorFlow 仅分配每个 GPU 总内存的 40%:
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.4
session = tf.Session(config=config)
【讨论】:
一个小提示...此信息是通过 tensorflow 指南获得的,关于如何将其与 gpu 一起使用:tensorflow.org/guide/using_gpu【参考方案4】:张量流 2
由于我们不再有会话,因此该解决方案不再可行。
默认情况下,TensorFlow 将几乎所有 GPU 的所有 GPU 内存(受 CUDA_VISIBLE_DEVICES 限制)映射到进程可见。
在某些情况下,希望进程只分配可用内存的子集,或者只增加进程所需的内存使用量。 TensorFlow 提供了两种方法来控制它。其中之一是使用set_memory_growthtf.config.experimental.set_memory_growth
为了全面了解,我推荐这个链接:Limiting GPU memory growth
【讨论】:
【参考方案5】:对于 TensorFlow 2:
config = tf.compat.v1.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.compat.v1.Session(config=config)
【讨论】:
【参考方案6】:来自TensorFlow guide
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
# Restrict TensorFlow to only allocate 1GB of memory on the first GPU
try:
tf.config.experimental.set_virtual_device_configuration(gpus[0],
[tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])
logical_gpus = tf.config.experimental.list_logical_devices('GPU')
print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
except RuntimeError as e:
# Virtual devices must be set before GPUs have been initialized
print(e)
将 memory_limit=*value*
调整为适合您的 GPU 的合理值。
例如从 Nvidia docker 容器和远程屏幕会话访问 1070ti,这是memory_limit=7168
,没有进一步的错误。只需确保偶尔清除 GPU 上的会话(例如 Jupyter 内核重新启动)。
【讨论】:
【参考方案7】:在深入研究上述其他可能的解释之前,请检查是否没有挂起的进程保留 GPU 内存。刚刚发生在我身上,我的 Tensorflow 脚本因某个错误而挂起,但我没有注意到它,因为我使用 nvidia-smi 监视正在运行的进程。现在挂起的脚本没有出现在 nvidia-smi 的输出中,但仍在保留 GPU 内存。杀死挂起的脚本(Tensorflow 通常会产生与系统中的 GPU 一样多的数量)完全解决了类似的问题(在用尽了所有 TF 魔法之后)。
【讨论】:
【参考方案8】:对于 TensorFlow 2 或 Keras:
from tensorflow.python.framework.config import set_memory_growth
tf.compat.v1.disable_v2_behavior()
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
try:
for gpu in gpus:
set_memory_growth(gpu, True)
except RuntimeError as e:
print(e)
【讨论】:
【参考方案9】:TensorFlow 数据集对象。这是一个高性能选项,更适用于不适合内存且从磁盘或分布式文件系统流式传输的数据集。
如果您有一个大型数据集并且在 GPU 上进行训练,请考虑使用 Dataset 对象,因为它们会处理对性能至关重要的细节,例如:
在 GPU 繁忙时在 CPU 上异步预处理数据,并将其缓冲到队列中。 在 GPU 内存上预取数据,以便在 GPU 完成上一个批次的处理后立即可用,这样您就可以充分利用 GPU。
tf.keras.preprocessing.image_dataset_from_directory 将分类到特定类别文件夹中的图像文件转换为图像张量的标记数据集。资源:https://keras.io/getting_started/intro_to_keras_for_engineers/
【讨论】:
您可以在“数据加载”部分找到此说明。以上是关于如何解决 TensorFlow 中的“gpu 内存不足”问题的主要内容,如果未能解决你的问题,请参考以下文章
如何防止 Tensorflow 在使用 Eager Execution 时分配全部 GPU 内存?