web-dev-qa-db-fra.com

Keras ne montre aucune amélioration de la vitesse d’entraînement avec le GPU (utilisation partielle du GPU?!)

J'essaie de former mon modèle sur un processeur graphique au lieu d'un processeur sur une instance AWS p2.xlarge de mon carnet de notes Jupyter. J'utilise le backend tensorflow-gpu (seul tensorflow-gpu a été installé et mentionné dans requirements.txt et non pas tensorflow).

Je ne constate aucune amélioration de la vitesse lors de la formation de modèles sur ces instances par rapport à l'utilisation d'un processeur. En fait, je reçois des vitesses de formation par époque pratiquement identiques à celles de mon processeur pour ordinateur portable à 4 cœurs (p2.xlarge dispose également de 4 vCPU avec un GPU Tesla K80). Je ne suis pas sûr d'avoir besoin d'apporter des modifications à mon code pour permettre un traitement plus rapide/parallèle que le processeur graphique peut offrir. Je colle ci-dessous mon code pour mon modèle:

model = Sequential()
model.add(recurrent.LSTM(64, input_shape=(X_np.shape[1], X_np.shape[2]),
                        return_sequences=True))
model.add(recurrent.LSTM(64, return_sequences = False))
model.add(core.Dropout(0.1))
model.add(core.Dense(3, activation='softmax'))
model.compile(loss = 'categorical_crossentropy', optimizer = 'rmsprop', metrics=['accuracy'])

model.fit(X_np, y_np, epochs=100, validation_split=0.25)

Il est également intéressant de noter que le GPU semble utiliser entre 50% et 60% de sa puissance de traitement et la quasi-totalité de sa mémoire chaque fois que je vérifie le statut du GPU à l'aide de nvidia-smi (mais les deux tombent respectivement à 0% et 1 Mo en l'absence de formation):

+-----------------------------------------------------------------------------+
| NVIDIA-SMI 384.81                 Driver Version: 384.81                    |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           On   | 00000000:00:1E.0 Off |                    0 |
| N/A   47C    P0    73W / 149W |  10919MiB / 11439MiB |     52%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|    0      1665      C   ...ubuntu/aDash/MLenv/bin/python 10906MiB |
+-----------------------------------------------------------------------------+

De plus, si vous souhaitez consulter mes journaux d'utilisation du GPU de Jupyter Notebook:

[I 04:21:59.390 NotebookApp] Kernel started: c17bc4d1-fa15-4b0e-b5f0-87f90e56bf65
[I 04:22:02.241 NotebookApp] Adapting to protocol v5.1 for kernel c17bc4d1-fa15-4b0e-b5f0-87f90e56bf65
2017-11-30 04:22:32.403981: I tensorflow/core/platform/cpu_feature_guard.cc:137] Your CPU supports instructions that this TensorFlow binary was not compiled to use: SSE4.1 SSE4.2 AVX AVX2 FMA
2017-11-30 04:22:33.653681: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:892] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2017-11-30 04:22:33.654041: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1030] Found device 0 with properties:
name: Tesla K80 major: 3 minor: 7 memoryClockRate(GHz): 0.8235
pciBusID: 0000:00:1e.0
totalMemory: 11.17GiB freeMemory: 11.10GiB
2017-11-30 04:22:33.654070: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7)
2017-11-30 04:22:34.014329: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7)
Device mapping:
/job:localhost/replica:0/task:0/device:GPU:0 -> device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7
2017-11-30 04:22:34.015339: I tensorflow/core/common_runtime/direct_session.cc:299] Device mapping:
/job:localhost/replica:0/task:0/device:GPU:0 -> device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7

2017-11-30 04:23:22.426895: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1120] Creating TensorFlow device (/device:GPU:0) -> (device: 0, name: Tesla K80, pci bus id: 0000:00:1e.0, compute capability: 3.7)

S'il vous plaît suggérer ce qui pourrait être le problème. Merci une tonne pour regarder ça quand même!

8
Ishaan Sejwal

Cela se produit parce que vous utilisez des couches LSTM. 

L'implémentation de Tensorflow pour les couches LSTM n'est pas si géniale. La raison en est probablement que les calculs récurrents ne sont pas des calculs parallèles et que les GPU sont parfaits pour le traitement parallèle. 

J'ai confirmé cela par ma propre expérience:

  • A obtenu une vitesse terrible en utilisant des LSTM dans mon modèle 
  • Décidé de tester le modèle en supprimant tous les LSTM (obtenu un modèle de convolution pur)
  • La vitesse résultante était tout simplement étonnante !!!

Cet article sur l’utilisation des GPU et de tensorflow confirme également que:

Une solution possible?

Vous pouvez essayer d’utiliser le nouveau CuDNNLSTM , qui semble préparé spécialement pour l’utilisation des GPU. 

Je ne l'ai jamais testé, mais vous obtiendrez probablement de meilleures performances avec cela.

Une autre chose que je n'ai pas testée, et je ne suis pas sûr que ce soit conçu pour cette raison, mais je suppose que c'est le cas: vous pouvez mettre unroll=True dans vos couches LSTM. Avec cela, je suppose que les calculs récurrents seront transformés en calculs parallèles.

16
Daniel Möller

Essayez d’utiliser une valeur plus grande pour batch_size dans model.fit, car la valeur par défaut est 32. Augmentez-le jusqu'à obtenir 100% d'utilisation du processeur.

Suivant les suggestions de @dgumo, vous pouvez également mettre vos données dans /run/shm. Il s’agit d’un système de fichiers en mémoire qui permet d’accéder aux données le plus rapidement possible. Sinon, vous pouvez vous assurer que vos données résident au moins sur SSD. Par exemple, dans /tmp.

2
mcsim

Le goulot d'étranglement dans votre cas est le transfert de données vers et depuis le GPU. Le meilleur moyen d'accélérer vos calculs (et d'optimiser l'utilisation de votre processeur graphique) est de charger autant de vos données que votre mémoire peut en contenir. Comme vous avez beaucoup de mémoire, vous pouvez mettre toutes vos données en même temps, en faisant:

model.fit(X_np, y_np, epochs=100, validation_split=0.25, batch_size=X_np.shape[0])

(Vous devriez aussi probablement augmenter le nombre d'époques lorsque vous faites cela).

Notez toutefois que la mini-correspondance présente des avantages (par exemple, une meilleure gestion des minima locaux), vous devriez donc probablement envisager de choisir un paramètre batch_size quelque part entre les deux.

1
Abderrahim Kitouni