tensorflow 了解 资源 耗尽 错误 :使用 形状 分配 张 量 时 的 OOM

v64noz0r  于 2022-11-16  发布在  其他
关注(0)|答案(8)|浏览(131)

我正在尝试使用tensorflow 实现一个跳跃思维模型,当前版本被放置在here .

目前,我使用计算机的一个GPU(共2个GPU),GPU信息为

2017-09-06 11:29:32.657299: I tensorflow/core/common_runtime/gpu/gpu_device.cc:940] Found device 0 with properties:
name: GeForce GTX 1080 Ti
major: 6 minor: 1 memoryClockRate (GHz) 1.683
pciBusID 0000:02:00.0
Total memory: 10.91GiB
Free memory: 10.75GiB

然而,当我尝试向模型输入数据时,我得到了OOM。我尝试如下调试:
在运行sess.run(tf.global_variables_initializer())之后,我使用了下面的代码片段

logger.info('Total: {} params'.format(
        np.sum([
            np.prod(v.get_shape().as_list())
            for v in tf.trainable_variables()
        ])))

得到2017-09-06 11:29:51,333 INFO main main.py:127 - Total: 62968629 params,如果全部使用tf.float32,则大致为240Mbtf.global_variables的输出为

[<tf.Variable 'embedding/embedding_matrix:0' shape=(155229, 200) dtype=float32_ref>,
 <tf.Variable 'encoder/rnn/gru_cell/gates/kernel:0' shape=(400, 400) dtype=float32_ref>,
 <tf.Variable 'encoder/rnn/gru_cell/gates/bias:0' shape=(400,) dtype=float32_ref>,
 <tf.Variable 'encoder/rnn/gru_cell/candidate/kernel:0' shape=(400, 200) dtype=float32_ref>,
 <tf.Variable 'encoder/rnn/gru_cell/candidate/bias:0' shape=(200,) dtype=float32_ref>,
 <tf.Variable 'decoder/weights:0' shape=(200, 155229) dtype=float32_ref>,
 <tf.Variable 'decoder/biases:0' shape=(155229,) dtype=float32_ref>,
 <tf.Variable 'decoder/previous_decoder/rnn/gru_cell/gates/kernel:0' shape=(400, 400) dtype=float32_ref>,
 <tf.Variable 'decoder/previous_decoder/rnn/gru_cell/gates/bias:0' shape=(400,) dtype=float32_ref>,
 <tf.Variable 'decoder/previous_decoder/rnn/gru_cell/candidate/kernel:0' shape=(400, 200) dtype=float32_ref>,
 <tf.Variable 'decoder/previous_decoder/rnn/gru_cell/candidate/bias:0' shape=(200,) dtype=float32_ref>,
 <tf.Variable 'decoder/next_decoder/rnn/gru_cell/gates/kernel:0' shape=(400, 400) dtype=float32_ref>,
 <tf.Variable 'decoder/next_decoder/rnn/gru_cell/gates/bias:0' shape=(400,) dtype=float32_ref>,
 <tf.Variable 'decoder/next_decoder/rnn/gru_cell/candidate/kernel:0' shape=(400, 200) dtype=float32_ref>,
 <tf.Variable 'decoder/next_decoder/rnn/gru_cell/candidate/bias:0' shape=(200,) dtype=float32_ref>,
 <tf.Variable 'global_step:0' shape=() dtype=int32_ref>]

在我的训练短语中,我有一个形状为(164652, 3, 30)的数据数组,即sample_size x 3 x time_step,这里的3表示前一句、当前句和下一句。这个训练数据的大小大约为57Mb,并存储在一个loader中。然后我使用编写一个生成器函数来获得句子,如下所示

def iter_batches(self, batch_size=128, time_major=True, shuffle=True):

    num_samples = len(self._sentences)
    if shuffle:
        samples = self._sentences[np.random.permutation(num_samples)]
    else:
        samples = self._sentences

    batch_start = 0
    while batch_start < num_samples:
        batch = samples[batch_start:batch_start + batch_size]

        lens = (batch != self._vocab[self._vocab.pad_token]).sum(axis=2)
        y, x, z = batch[:, 0, :], batch[:, 1, :], batch[:, 2, :]
        if time_major:
            yield (y.T, lens[:, 0]), (x.T, lens[:, 1]), (z.T, lens[:, 2])
        else:
            yield (y, lens[:, 0]), (x, lens[:, 1]), (z, lens[:, 2])
        batch_start += batch_size

训练循环如下所示

for epoch in num_epochs:
    batches = loader.iter_batches(batch_size=args.batch_size)
    try:
        (y, y_lens), (x, x_lens), (z, z_lens) =  next(batches)
        _, summaries, loss_val = sess.run(
        [train_op, train_summary_op, st.loss],
        feed_dict={
            st.inputs: x,
            st.sequence_length: x_lens,
            st.previous_targets: y,
            st.previous_target_lengths: y_lens,
            st.next_targets: z,
            st.next_target_lengths: z_lens
        })
    except StopIteraton:
        ...

然后我得到了一个OOM。如果我注解掉整个try主体(不馈送数据),脚本运行得很好。
我不知道为什么我会在这么小的数据规模下得到OOM。

Wed Sep  6 12:03:37 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.59                 Driver Version: 384.59                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 108...  Off  | 00000000:02:00.0 Off |                  N/A |
|  0%   44C    P2    60W / 275W |  10623MiB / 11172MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
|   1  GeForce GTX 108...  Off  | 00000000:03:00.0 Off |                  N/A |
|  0%   43C    P2    62W / 275W |  10621MiB / 11171MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID  Type  Process name                               Usage      |
|=============================================================================|
|    0     32748    C   python3                                      10613MiB |
|    1     32748    C   python3                                      10611MiB |
+-----------------------------------------------------------------------------+

我 * 不能 * 看到我的脚本的 * 实际 * GPU使用情况,因为tensorflow总是在开始时窃取所有内存。
我在StackOverflow上读过一些关于面向对象的帖子。大多数都是在向模型提供大的测试集数据时发生的,通过小批量提供数据可以避免这个问题。但我不明白为什么在我的11Gb 1080Ti中看到这么小的数据和参数组合会很糟糕,因为错误只是试图分配一个大小为[3840 x 155229]的矩阵。(解码器的输出矩阵3840 = 30(time_steps) x 128(batch_size)155229为vocab_size)。

2017-09-06 12:14:45.787566: W tensorflow/core/common_runtime/bfc_allocator.cc:277] ********************************************************************************************xxxxxxxx
2017-09-06 12:14:45.787597: W tensorflow/core/framework/op_kernel.cc:1158] Resource exhausted: OOM when allocating tensor with shape[3840,155229]
2017-09-06 12:14:45.788735: W tensorflow/core/framework/op_kernel.cc:1158] Resource exhausted: OOM when allocating tensor with shape[3840,155229]
     [[Node: decoder/previous_decoder/Add = Add[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/gpu:0"](decoder/previous_decoder/MatMul, decoder/biases/read)]]
2017-09-06 12:14:45.790453: I tensorflow/core/common_runtime/gpu/pool_allocator.cc:247] PoolAllocator: After 2857 get requests, put_count=2078 evicted_count=1000 eviction_rate=0.481232 and unsatisfied allocation rate=0.657683
2017-09-06 12:14:45.790482: I tensorflow/core/common_runtime/gpu/pool_allocator.cc:259] Raising pool_size_limit_ from 100 to 110
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/client/session.py", line 1139, in _do_call
    return fn(*args)
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/client/session.py", line 1121, in _run_fn
    status, run_metadata)
  File "/usr/lib/python3.6/contextlib.py", line 88, in __exit__
    next(self.gen)
  File "/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/errors_impl.py", line 466, in raise_exception_on_not_ok_status
    pywrap_tensorflow.TF_GetCode(status))
tensorflow.python.framework.errors_impl.ResourceExhaustedError: OOM when allocating tensor with shape[3840,155229]
     [[Node: decoder/previous_decoder/Add = Add[T=DT_FLOAT, _device="/job:localhost/replica:0/task:0/gpu:0"](decoder/previous_decoder/MatMul, decoder/biases/read)]]
     [[Node: GradientDescent/update/_146 = _Recv[client_terminated=false, recv_device="/job:localhost/replica:0/task:0/cpu:0", send_device="/job:localhost/replica:0/task:0/gpu:0", send_device_incarnation=1, tensor_name="edge_2166_GradientDescent/update", tensor_type=DT_FLOAT, _device="/job:localhost/replica:0/task:0/cpu:0"]()]]

During handling of the above exception, another exception occurred:

任何帮助都将不胜感激。提前感谢。

afdcj2ne

afdcj2ne1#

让我们把问题一个一个地划分:
关于tensorflow预先分配所有内存,你可以使用下面的代码片段让tensorflow在需要的时候分配内存,这样你就可以了解事情是如何进行的。

gpu_options = tf.GPUOptions(allow_growth=True)
session = tf.InteractiveSession(config=tf.ConfigProto(gpu_options=gpu_options))

如果您愿意,这与tf.Session()(而不是tf.InteractiveSession())同样适用。
关于大小的第二件事,由于没有关于网络大小的信息,我们无法估计出哪里出了问题。但是,您也可以一步一步地调试整个网络。例如,创建一个只有一层的网络,获取其输出,创建会话并输入值一次,然后可视化您消耗了多少内存。迭代此调试会话,直到您看到内存不足的点。
请注意,3840 x 155229的输出是一个非常非常大的输出。这意味着~ 600 M的神经元,每层~2.22GB。如果你有任何类似大小的层,所有这些层加起来会很快填满你的GPU内存。
此外,这仅适用于正向,如果您将此层用于训练,则反向传播和优化程序添加的层将使此大小乘以2。因此,训练仅输出层就占用约5 GB。
我建议您修改网络,并尝试减少批处理大小/参数计数,以使模型适合GPU

cotxawn7

cotxawn72#

这在技术上可能没有意义,但经过一段时间的实验,这就是我所发现的。

环境:Ubuntu 16.04版

运行命令时
英伟达
您将获得已安装的Nvidia显卡的总内存消耗。示例如下图

所示
运行神经网络后,消耗量可能会更改为

内存消耗通常是由python提供的。由于某种奇怪的原因,如果这个进程未能成功终止,内存将永远不会被释放。如果您尝试运行神经网络应用程序的另一个示例,您将收到内存分配错误。困难的方法是尝试找出一种使用进程ID终止这个进程的方法。例如,对于进程ID 2794,您可以

sudo kill -9 2794

最简单的方法是重新启动计算机,然后再试一次。但是,如果是与代码相关的错误,这将不起作用。
如果上述过程不起作用,则可能是您使用的数据批处理大小无法放入GPU或CPU内存。
你可以做的是减少批处理大小或输入数据的空间维度(长度、宽度和深度)。这可能会起作用,但你可能会用完RAM。
保存RAM的最可靠的方法是使用函数发生器,这本身就是主题。

trnvg8h3

trnvg8h33#

您正在耗尽内存,您可以减少批处理大小,这将减慢定型过程,但可以使您拟合数据。

uyto3xhc

uyto3xhc4#

我知道你的问题是关于tensorflow的。无论如何,使用Kerastensorflow-backend是我的用例,并导致了相同的 OOM-错误。
我使用Keras和tf-backend的解决方案是使用Keras的fit_generator()-方法。在此之前,我只使用fit()-方法(导致 OOM-错误)。
fit_generator()通常适用于无法将数据放入主内存或必须在GPU训练的同时访问CPU资源的情况。

  • 为了提高效率,生成器与模型并行运行。例如,这允许您在CPU上对图像进行实时数据扩充,同时在GPU上训练模型。*

显然,这也可以帮助防止内存溢出从您的图形卡内存。

  • 编辑:如果您需要一些灵感来开发自己的(线程安全)生成器,扩展Keras的Sequence-类,然后将其用于fit_generator(),您可以查看我在本问答中提供的一些信息。*
5cnsuln7

5cnsuln75#

我在使用EfficientNet模型应用迁移学习时遇到了这个错误。我可以通过冻结Conv层来解决这个问题:

base_model = EfficientNetB0(include_top=False, input_tensor=...)
for layer in base_model.layers:
    layer.trainable=False
b91juud3

b91juud36#

我有一个内存问题。在我的情况下,我只是减少了批大小。😀

du7egjpx

du7egjpx7#

您可以减小批处理大小,尽管您可能会发现结果(型号性能)不同(通常性能较低)。某些模型在批处理较大时性能可能较好。它们可能收敛得更快。否则,模型在批处理较小时可能需要更多时期。在这种情况下,训练时间可能会更长。尤其是现在您已经添加了更多的时期并采用了更小的批量。
没有比耐心更长的训练时间的解决方案,因为这意味着如果你想要更快的计算,你需要更大RAM的GPU:)

chhkpiq4

chhkpiq48#

重新启动jupyter笔记本对我很有效

相关问题