web-dev-qa-db-fra.com

Compréhension de ResourceExhaustedError: MOO lors de l’affectation d’un tenseur avec une forme

J'essaie d'implémenter un modèle de pensée sauté en utilisant tensorflow et une version actuelle est placée ici .  enter image description here

Actuellement, j'utilise un GPU de ma machine (2 au total) et les informations du GPU sont

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

Cependant, j'ai eu OOM lorsque j'essaie de fournir des données au modèle. J'essaye de déboguer comme suit:

J'utilise l'extrait suivant juste après l'exécution de 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()
        ])))

et obtenu 2017-09-06 11:29:51,333 INFO main main.py:127 - Total: 62968629 params, à peu près environ 240Mb si tous utilisent tf.float32. La sortie de tf.global_variables est 

[<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>]

Dans ma phrase de formation, j'ai un tableau de données dont la forme est (164652, 3, 30), à savoir sample_size x 3 x time_step, le 3 signifie ici la phrase précédente, la phrase actuelle et la phrase suivante. La taille de ces données d'apprentissage est d'environ 57Mb et est stockée dans une loader. Ensuite, j'écris une fonction de générateur pour obtenir les phrases.

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

La boucle de formation ressemble à

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:
        ...

Ensuite, j'ai un OOM. Si je commente l'ensemble du corps try (non alimenté en données), le script s'exécute parfaitement.

Je ne sais pas pourquoi j'ai eu OOM dans une aussi petite échelle de données. En utilisant nvidia-smi j'ai toujours eu 

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 |
+-----------------------------------------------------------------------------+

Je ne peux pas voir l'utilisation de mon script par le GPU reel, car tensorflow vole toujours toute la mémoire au début. Et le problème actuel est que je ne sais pas comment résoudre ce problème.

J'ai lu des articles sur OOM sur StackOverflow. La plupart d’entre eux se sont produits lorsqu’on a transmis au modèle des données sur un ensemble de tests volumineux et que l’alimentation des données par petits lots peut éviter le problème. Mais je ne vois pas pourquoi voir une si petite combinaison de données et de paramètres aspirer dans mon 11Gb 1080Ti, car l'erreur consiste simplement à allouer une matrice de la taille [3840 x 155229]. (La matrice de sortie du décodeur, 3840 = 30(time_steps) x 128(batch_size), 155229 est 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:

Toute aide serait appréciée. Merci d'avance.

5
Edityouprofile

Divisons les problèmes un par un:

À propos de tensorflow pour allouer toute la mémoire à l’avance, vous pouvez utiliser l’extrait de code suivant pour permettre à tensorflow d’allouer de la mémoire chaque fois que cela est nécessaire. Pour que vous puissiez comprendre comment vont les choses.

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

Cela fonctionne également avec tf.Session() au lieu de tf.InteractiveSession() si vous préférez.

Deuxième chose à propos des tailles, Comme il n’ya pas d’information sur la taille de votre réseau, nous ne pouvons pas estimer ce qui ne va pas. Cependant, vous pouvez également déboguer pas à pas tout le réseau. Par exemple, créez un réseau avec une seule couche, obtenez sa sortie, créez une session et alimentez les valeurs une seule fois et visualisez la quantité de mémoire utilisée. Itérez cette session de débogage jusqu'à ce que vous voyiez le point où vous manquez de mémoire. 

S'il vous plaît être conscient que 3840 x 155229 sortie est vraiment, vraiment une grande sortie. Cela signifie ~ 600 millions de neurones et environ 2,22 Go par couche. Si vous avez des couches de taille similaire, elles s’ajouteront pour remplir votre mémoire GPU assez rapidement. 

De plus, ceci est uniquement pour le sens avant. Si vous utilisez cette couche pour la formation, la propagation en arrière et les couches ajoutées par l'optimiseur multiplieront cette taille par 2. Donc, pour la formation, vous utilisez environ 5 Go uniquement pour la couche en sortie. 

Je vous suggère de réviser votre réseau et d'essayer de réduire le nombre de lots/paramètres pour adapter votre modèle au GPU

7
Deniz Beker

Techniquement, cela n’a aucun sens, mais c’est ce que j’ai découvert après des expériences.

ENVIRONNEMENT: Ubuntu 16.04


Lorsque vous exécutez la commande 

nvidia-smi

Vous obtiendrez la consommation totale de mémoire de la carte graphique Nvidia installée. Un exemple est comme indiqué dans cette image  enter image description here

Lorsque vous avez exécuté votre réseau de neurones, votre consommation peut changer pour ressembler à  enter image description here

La consommation de mémoire est généralement attribuée à python. Pour une raison étrange, si ce processus échoue, la mémoire n'est jamais libérée. Si vous essayez d'exécuter une autre instance de l'application de réseau neuronal, vous êtes sur le point de recevoir une erreur d'allocation de mémoire. Le plus difficile est d'essayer de trouver un moyen de mettre fin à ce processus en utilisant l'ID de processus. Le moyen le plus simple est de simplement redémarrer votre ordinateur et d’essayer à nouveau. S'il s'agit d'un bogue lié au code, cela ne fonctionnera pas. 

5
rocksyne

Vous épuisez votre mémoire. Vous pouvez réduire la taille du lot, ce qui ralentirait le processus d’entraînement mais vous permettrait d’ajuster les données.

0
Jibin Mathew