Keras utilise beaucoup trop de mémoire GPU lors de l'appel train sur batch, fit, etc
J'ai joué avec Keras, et j'aime ça jusqu'à présent. Il y a un gros problème que j'ai eu, quand je travaillais avec des réseaux assez profonds: quand j'appelais model.train_on_batch, ou d'un modèle.ajustement etc., Keras alloue beaucoup plus de mémoire GPU que ce dont le modèle lui-même devrait avoir besoin. Ceci n'est pas causé par le fait d'essayer de s'entraîner sur de très grandes images, c'est le modèle de réseau lui-même qui semble nécessiter beaucoup de mémoire GPU. J'ai créé cet exemple de jouet pour montrer ce que je veux dire. Voici essentiellement ce qui se passe:
je crée d'abord un réseau assez profond, et utilise le modèle.résumé() pour obtenir le nombre total de paramètres nécessaires pour le réseau (dans ce cas 206538153, ce qui correspond à environ 826 MO). J'utilise ensuite nvidia-smi pour voir combien de Kera mémoire GPU a alloué, et je peux voir que cela a un sens parfait (849 MB).
je compile alors le réseau, et je peux confirmer que cela n'augmente pas l'utilisation de la mémoire GPU. Et comme nous pouvons le voir dans ce cas, J'ai presque 1 Go de VRAM disponible à ce point.
ensuite j'essaie de nourrir une image 16x16 simple et une vérité de fond 1x1 au réseau, et puis tout explose, parce que Keras commence à allouer beaucoup de mémoire à nouveau, pour aucune raison qui est évidente pour moi. Quelque chose à propos de la formation du réseau semble exiger beaucoup plus de mémoire que juste avoir le modèle, ce qui n'a pas de sens pour moi. J'ai formé des réseaux beaucoup plus profonds sur ce GPU dans d'autres cadres, de sorte que cela me fait penser que J'utilise mal Keras (ou qu'il y a quelque chose de mal dans ma configuration, ou dans Keras, mais bien sûr c'est difficile à savoir avec certitude).
voici le code:
from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os
model = Sequential()
model.add(Convolution2D(256, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(512, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(Convolution2D(1024, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2), strides=(2,2)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))
model.summary()
os.system("nvidia-smi")
raw_input("Press Enter to continue...")
model.compile(optimizer='sgd',
loss='mse',
metrics=['accuracy'])
os.system("nvidia-smi")
raw_input("Compiled model. Press Enter to continue...")
n_batches = 1
batch_size = 1
for ibatch in range(n_batches):
x = np.random.rand(batch_size, 16,16,1)
y = np.random.rand(batch_size, 1)
os.system("nvidia-smi")
raw_input("About to train one iteration. Press Enter to continue...")
model.train_on_batch(x, y)
print("Trained one iteration")
qui donne la sortie suivante pour moi:
Using Theano backend.
Using gpu device 0: GeForce GTX 960 (CNMeM is disabled, cuDNN 5103)
/usr/local/lib/python2.7/dist-packages/theano/sandbox/cuda/__init__.py:600: UserWarning: Your cuDNN version is more recent than the one Theano officially supports. If you see any problems, try updating Theano or downgrading cuDNN to version 5.
warnings.warn(warn)
____________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
====================================================================================================
convolution2d_1 (Convolution2D) (None, 16, 16, 256) 2560 convolution2d_input_1[0][0]
____________________________________________________________________________________________________
maxpooling2d_1 (MaxPooling2D) (None, 8, 8, 256) 0 convolution2d_1[0][0]
____________________________________________________________________________________________________
convolution2d_2 (Convolution2D) (None, 8, 8, 512) 1180160 maxpooling2d_1[0][0]
____________________________________________________________________________________________________
maxpooling2d_2 (MaxPooling2D) (None, 4, 4, 512) 0 convolution2d_2[0][0]
____________________________________________________________________________________________________
convolution2d_3 (Convolution2D) (None, 4, 4, 1024) 4719616 maxpooling2d_2[0][0]
____________________________________________________________________________________________________
convolution2d_4 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_3[0][0]
____________________________________________________________________________________________________
convolution2d_5 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_4[0][0]
____________________________________________________________________________________________________
convolution2d_6 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_5[0][0]
____________________________________________________________________________________________________
convolution2d_7 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_6[0][0]
____________________________________________________________________________________________________
convolution2d_8 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_7[0][0]
____________________________________________________________________________________________________
convolution2d_9 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_8[0][0]
____________________________________________________________________________________________________
convolution2d_10 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_9[0][0]
____________________________________________________________________________________________________
convolution2d_11 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_10[0][0]
____________________________________________________________________________________________________
convolution2d_12 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_11[0][0]
____________________________________________________________________________________________________
convolution2d_13 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_12[0][0]
____________________________________________________________________________________________________
convolution2d_14 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_13[0][0]
____________________________________________________________________________________________________
convolution2d_15 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_14[0][0]
____________________________________________________________________________________________________
convolution2d_16 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_15[0][0]
____________________________________________________________________________________________________
convolution2d_17 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_16[0][0]
____________________________________________________________________________________________________
convolution2d_18 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_17[0][0]
____________________________________________________________________________________________________
convolution2d_19 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_18[0][0]
____________________________________________________________________________________________________
convolution2d_20 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_19[0][0]
____________________________________________________________________________________________________
convolution2d_21 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_20[0][0]
____________________________________________________________________________________________________
convolution2d_22 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_21[0][0]
____________________________________________________________________________________________________
convolution2d_23 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_22[0][0]
____________________________________________________________________________________________________
convolution2d_24 (Convolution2D) (None, 4, 4, 1024) 9438208 convolution2d_23[0][0]
____________________________________________________________________________________________________
maxpooling2d_3 (MaxPooling2D) (None, 2, 2, 1024) 0 convolution2d_24[0][0]
____________________________________________________________________________________________________
convolution2d_25 (Convolution2D) (None, 2, 2, 256) 2359552 maxpooling2d_3[0][0]
____________________________________________________________________________________________________
convolution2d_26 (Convolution2D) (None, 2, 2, 32) 73760 convolution2d_25[0][0]
____________________________________________________________________________________________________
maxpooling2d_4 (MaxPooling2D) (None, 1, 1, 32) 0 convolution2d_26[0][0]
____________________________________________________________________________________________________
flatten_1 (Flatten) (None, 32) 0 maxpooling2d_4[0][0]
____________________________________________________________________________________________________
dense_1 (Dense) (None, 4) 132 flatten_1[0][0]
____________________________________________________________________________________________________
dense_2 (Dense) (None, 1) 5 dense_1[0][0]
====================================================================================================
Total params: 206538153
____________________________________________________________________________________________________
None
Thu Oct 6 09:05:42 2016
+------------------------------------------------------+
| NVIDIA-SMI 352.63 Driver Version: 352.63 |
|-------------------------------+----------------------+----------------------+
| 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 960 Off | 0000:01:00.0 On | N/A |
| 30% 37C P2 28W / 120W | 1082MiB / 2044MiB | 9% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1796 G /usr/bin/X 155MiB |
| 0 2597 G compiz 65MiB |
| 0 5966 C python 849MiB |
+-----------------------------------------------------------------------------+
Press Enter to continue...
Thu Oct 6 09:05:44 2016
+------------------------------------------------------+
| NVIDIA-SMI 352.63 Driver Version: 352.63 |
|-------------------------------+----------------------+----------------------+
| 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 960 Off | 0000:01:00.0 On | N/A |
| 30% 38C P2 28W / 120W | 1082MiB / 2044MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1796 G /usr/bin/X 155MiB |
| 0 2597 G compiz 65MiB |
| 0 5966 C python 849MiB |
+-----------------------------------------------------------------------------+
Compiled model. Press Enter to continue...
Thu Oct 6 09:05:44 2016
+------------------------------------------------------+
| NVIDIA-SMI 352.63 Driver Version: 352.63 |
|-------------------------------+----------------------+----------------------+
| 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 960 Off | 0000:01:00.0 On | N/A |
| 30% 38C P2 28W / 120W | 1082MiB / 2044MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1796 G /usr/bin/X 155MiB |
| 0 2597 G compiz 65MiB |
| 0 5966 C python 849MiB |
+-----------------------------------------------------------------------------+
About to train one iteration. Press Enter to continue...
Error allocating 37748736 bytes of device memory (out of memory). Driver report 34205696 bytes free and 2144010240 bytes total
Traceback (most recent call last):
File "memtest.py", line 65, in <module>
model.train_on_batch(x, y)
File "/usr/local/lib/python2.7/dist-packages/keras/models.py", line 712, in train_on_batch
class_weight=class_weight)
File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1221, in train_on_batch
outputs = self.train_function(ins)
File "/usr/local/lib/python2.7/dist-packages/keras/backend/theano_backend.py", line 717, in __call__
return self.function(*inputs)
File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 871, in __call__
storage_map=getattr(self.fn, 'storage_map', None))
File "/usr/local/lib/python2.7/dist-packages/theano/gof/link.py", line 314, in raise_with_op
reraise(exc_type, exc_value, exc_trace)
File "/usr/local/lib/python2.7/dist-packages/theano/compile/function_module.py", line 859, in __call__
outputs = self.fn()
MemoryError: Error allocating 37748736 bytes of device memory (out of memory).
Apply node that caused the error: GpuContiguous(GpuDimShuffle{3,2,0,1}.0)
Toposort index: 338
Inputs types: [CudaNdarrayType(float32, 4D)]
Inputs shapes: [(1024, 1024, 3, 3)]
Inputs strides: [(1, 1024, 3145728, 1048576)]
Inputs values: ['not shown']
Outputs clients: [[GpuDnnConv{algo='small', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0}), GpuDnnConvGradI{algo='none', inplace=True}(GpuContiguous.0, GpuContiguous.0, GpuAllocEmpty.0, GpuDnnConvDesc{border_mode='half', subsample=(1, 1), conv_mode='conv', precision='float32'}.0, Constant{1.0}, Constant{0.0})]]
HINT: Re-running with most Theano optimization disabled could give you a back-trace of when this node was created. This can be done with by setting the Theano flag 'optimizer=fast_compile'. If that does not work, Theano optimizations can be disabled with 'optimizer=None'.
HINT: Use the Theano flag 'exception_verbosity=high' for a debugprint and storage map footprint of this apply node.
quelques points à noter:
- j'ai essayé à la fois Theano et TensorFlow backends. Les deux ont les mêmes problèmes, et exécuter de mémoire à la même ligne. Dans TensorFlow, il semble que Keras préalloque beaucoup de mémoire (environ 1,5 Go) donc nvidia-smi ne nous aide pas à suivre ce qui se passe là-bas, mais je reçois les mêmes exceptions hors de la mémoire. Encore une fois, cela indique une erreur dans (mon usage de) Keras (bien qu'il soit difficile d'être certain de telles choses, cela pourrait être quelque chose avec ma configuration).
- j'ai essayé D'utiliser CNMEM à Theano, qui se comporte comme TensorFlow: il préalloque une grande quantité de mémoire (environ 1,5 Go) encore se bloque dans le même endroit.
- il y a quelques avertissements à propos de la version CudNN. J'ai essayé D'exécuter le backend de Theano avec CUDA mais pas CudNN et j'ai eu les mêmes erreurs, donc ce n'est pas la source du problème.
- si vous voulez tester ceci sur votre propre GPU, vous pourriez vouloir rendre le réseau plus profond/moins profond en fonction de la quantité de mémoire GPU que vous avez à tester cela.
- ma configuration est la suivante: Ubuntu 14.04, GeForce GTX 960, CUDA 7.5.18, CudNN 5.1.3, Python 2.7, Keras 1.1.0 (installé via pip)
- j'ai essayé de changer la compilation du modèle pour utiliser différents optimiseurs et pertes, mais cela ne semble pas changer quoi que ce soit.
- j'ai essayé de changer la fonction train_on_batch pour utiliser fit à la place, mais elle a le même problème.
- j'ai vu une question similaire ici sur StackOverflow - pourquoi Ce modèle Keras nécessite plus de 6 Go de mémoire? - mais pour autant que je sache, je n'ai pas ces problèmes dans ma configuration. Je n'ai jamais eu plusieurs versions de CUDA installées, et j'ai vérifié mon chemin, les variables LD_LIBRARY_PATH et CUDA_ROOT plus de fois que je ne peux les Compter.
- Julius a suggéré que les paramètres d'activation eux-mêmes prennent la mémoire GPU. Si cela est vrai, quelqu'un peut-il expliquer un peu plus clairement? J'ai essayé de changer la fonction d'activation de mon convolution couches de fonctions qui sont clairement codés sans aucun paramètre d'apprentissage, d'après ce que je peux dire, et ça ne change rien. Aussi, il semble peu probable que ces paramètres ne prennent presque autant de mémoire que le reste du réseau lui-même.
- après des tests approfondis, le plus grand réseau que je puisse former est d'environ 453 MB de paramètres, sur mon ~2 Go de GPU RAM. Est-ce normal?
- après avoir testé des Kéras sur des petits CNN qui s'adaptent à mon GPU, je peux voir que il y a des pointes très soudaines dans L'utilisation de la mémoire vive GPU. Si j'exécute un réseau avec environ 100 Mo de paramètres, 99% du temps pendant l'entraînement, il utilisera moins de 200 Mo de mémoire vive GPU. Mais de temps en temps, l'utilisation de la mémoire monte à environ 1,3 Go. Il semble sûr de supposer que ce sont ces pointes qui causent mes problèmes. Je n'ai jamais vu ces pointes dans d'autres cadres, mais ils pourraient être là pour une bonne raison? si quelqu'un sait ce qui les cause, et s'il y a un moyen de les éviter, s'il vous plaît carillon!
3 réponses
c'est une erreur très commune d'oublier que les activations et les gradients prennent aussi vram, pas seulement les paramètres, augmentant l'utilisation de la mémoire un peu. Les calculs de backprob eux-mêmes le font de sorte que la phase de formation prend presque le double de la VRAM de l'utilisation d'avant / inférence du réseau neuronal.
ainsi, au début lorsque le réseau est créé, seuls les paramètres sont attribués. Cependant, quand la formation commence, les activations (fois chaque minibatch) obtiennent alloué, ainsi que les calculs backprop, augmentant l'utilisation de la mémoire.
à la fois Theano et Tensorflow augmente le graphique symbolique qui est créé, bien que les deux différemment.
pour analyser comment la consommation de mémoire se produit, vous pouvez commencer par un modèle plus petit et le faire pousser pour voir la croissance correspondante dans la mémoire. De même, vous pouvez faire pousser le batch_size
pour voir la croissance correspondante dans la mémoire.
voici un extrait de code pour augmenter batch_size
basé sur votre code initial:
from scipy import misc
import numpy as np
from keras.models import Sequential
from keras.layers import Dense, Activation, Convolution2D, MaxPooling2D, Reshape, Flatten, ZeroPadding2D, Dropout
import os
import matplotlib.pyplot as plt
def gpu_memory():
out = os.popen("nvidia-smi").read()
ret = '0MiB'
for item in out.split("\n"):
if str(os.getpid()) in item and 'python' in item:
ret = item.strip().split(' ')[-2]
return float(ret[:-3])
gpu_mem = []
gpu_mem.append(gpu_memory())
model = Sequential()
model.add(Convolution2D(100, 3, 3, border_mode='same', input_shape=(16,16,1)))
model.add(Convolution2D(256, 3, 3, border_mode='same'))
model.add(Convolution2D(32, 3, 3, border_mode='same'))
model.add(MaxPooling2D(pool_size=(2,2)))
model.add(Flatten())
model.add(Dense(4))
model.add(Dense(1))
model.summary()
gpu_mem.append(gpu_memory())
model.compile(optimizer='sgd',
loss='mse',
metrics=['accuracy'])
gpu_mem.append(gpu_memory())
batches = []
n_batches = 20
batch_size = 1
for ibatch in range(n_batches):
batch_size = (ibatch+1)*10
batches.append(batch_size)
x = np.random.rand(batch_size, 16,16,1)
y = np.random.rand(batch_size, 1)
print y.shape
model.train_on_batch(x, y)
print("Trained one iteration")
gpu_mem.append(gpu_memory())
fig = plt.figure()
plt.plot([-100, -50, 0]+batches, gpu_mem)
plt.show()
aussi, pour la vitesse Tensorflow hogs jusqu'à la mémoire GPU tout disponible. Pour arrêter cela, et vous devez ajouter config.gpu_options.allow_growth = True
dans get_session()
# keras/backend/tensorflow_backend.py
def get_session():
global _SESSION
if tf.get_default_session() is not None:
session = tf.get_default_session()
else:
if _SESSION is None:
if not os.environ.get('OMP_NUM_THREADS'):
config = tf.ConfigProto(allow_soft_placement=True,
)
else:
nb_thread = int(os.environ.get('OMP_NUM_THREADS'))
config = tf.ConfigProto(intra_op_parallelism_threads=nb_thread,
allow_soft_placement=True)
config.gpu_options.allow_growth = True
_SESSION = tf.Session(config=config)
session = _SESSION
if not _MANUAL_VAR_INIT:
_initialize_variables()
return session
maintenant, si vous lancez le prev snippet vous obtenez des tracés comme:
Theano: après model.compile()
quelle que soit la mémoire nécessaire, au début de l'entraînement, il double presque. Cela est dû au fait que Theano augmente le graphe symbolique pour faire de la rétro-propagation et que chaque tenseur a besoin d'un tenseur correspondant pour obtenir le flux de gradients vers l'arrière. Les besoins de mémoire ne semblent pas augmenter avec batch_size
et cela est inattendu pour moi que la taille des espaces devrait augmenter pour accommoder l'entrée de données de CPU->GPU.
Tensorflow: aucune mémoire GPU n'est attribuée même après model.compile()
car les Keras ne appelez get_session()
jusqu'à cette heure qui appelle en fait _initialize_variables()
. Tensorflow semble monopoliser la mémoire en morceaux pour la vitesse et donc la mémoire ne se développe pas linéairement avec batch_size
.
ayant dit tout que Tensorflow semble avoir faim de mémoire mais pour les grands graphiques son très rapide.. Theano d'un autre côté est très efficace de mémoire gpu, mais prend beaucoup de temps pour initialiser le graphe au début de l'entraînement. Après que sa aussi très vite.
200m params pour 2 Go GPU est trop. En outre, votre architecture Non efficace, en utilisant des goulots d'étranglement locaux sera plus efficace. Aussi, vous devriez passer du petit modèle au grand, et pas en arrière, en ce moment vous avez input 16x16, avec cette architecture qui signifie qu'à la fin la plupart de votre réseau sera "zero padded" et pas basé sur des fonctionnalités d'entrée. Vos calques de modèle dépendent de votre entrée, de sorte que vous ne pouvez pas juste définir le nombre arbitraire de calques et de tailles, vous devez compter combien de données seront transmis à chacun d'eux, à comprendre pourquoi le font. Je vous recommande de regarder ce cours gratuit http://cs231n.github.io