Aide à protéger la Grande barrière de corail avec tensorflow sur Kaggle Rejoignez Défi

Utiliser un GPU

Voir sur TensorFlow.org Exécuter dans Google Colab Voir la source sur GitHub Télécharger le cahier

Le code tensorflow et tf.keras modèles fonctionneront en toute transparence sur un seul GPU sans changement de code requis.

La façon la plus simple à exécuter sur plusieurs processeurs graphiques, sur une ou plusieurs machines, utilise des stratégies de distribution .

Ce guide est destiné aux utilisateurs qui ont essayé ces approches et qui ont constaté qu'ils ont besoin d'un contrôle précis de la façon dont TensorFlow utilise le GPU. Pour savoir comment déboguer les problèmes de performance pour les scénarios simples et multi-GPU, consultez la performance GPU Optimize tensorflow guide.

Installer

Assurez-vous que la dernière version du GPU TensorFlow est installée.

import tensorflow as tf
print("Num GPUs Available: ", len(tf.config.list_physical_devices('GPU')))
Num GPUs Available:  1

Aperçu

TensorFlow prend en charge l'exécution de calculs sur divers types d'appareils, notamment le processeur et le processeur graphique. Ils sont représentés par des identifiants de chaîne par exemple :

  • "/device:CPU:0" : La CPU de votre machine.
  • "/GPU:0" : la notation sténographique pour le premier GPU de votre machine qui est visible à tensorflow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : Nom complet du deuxième GPU de votre machine qui est visible à tensorflow.

Si une opération TensorFlow a à la fois des implémentations CPU et GPU, par défaut, le périphérique GPU est prioritaire lorsque l'opération est attribuée. Par exemple, tf.matmul possède à la fois CPU et GPU noyaux et sur un système avec les périphériques CPU:0 et GPU:0 , le GPU:0 appareil est sélectionné pour exécuter tf.matmul sauf si vous demandez explicitement de l' exécuter sur un autre appareil.

Si une opération TensorFlow n'a pas d'implémentation GPU correspondante, l'opération revient au périphérique CPU. Par exemple, étant donné que tf.cast ne dispose que d' un noyau CPU, sur un système avec les périphériques CPU:0 et GPU:0 , la CPU:0 appareil est sélectionné pour l' exécution tf.cast , même si la demande de fonctionner sur le GPU:0 dispositif .

Emplacement du périphérique de journalisation

Pour savoir quels appareils vos opérations et tenseurs sont affectés à, mis tf.debugging.set_log_device_placement(True) comme la première déclaration de votre programme. L'activation de la journalisation du placement des périphériques entraîne l'impression de toutes les allocations ou opérations Tensor.

tf.debugging.set_log_device_placement(True)

# Create some tensors
a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
c = tf.matmul(a, b)

print(c)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Le code ci - dessus affichera une indication du MatMul op a été exécuté le GPU:0 .

Placement manuel de l'appareil

Si vous souhaitez une opération particulière pour fonctionner sur un dispositif de votre choix au lieu de ce qui est automatiquement sélectionné pour vous, vous pouvez utiliser with tf.device pour créer un contexte de périphérique, et toutes les opérations dans ce contexte courrez sur le même appareil désigné .

tf.debugging.set_log_device_placement(True)

# Place tensors on the CPU
with tf.device('/CPU:0'):
  a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
  b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])

# Run on the GPU
c = tf.matmul(a, b)
print(c)
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Vous verrez que maintenant a et b sont affectés au CPU:0 . Etant donné qu'un appareil n'a pas été spécifié explicitement pour la MatMul opération, le moteur d' exécution de tensorflow choisira un basé sur l'exploitation et les périphériques disponibles ( GPU:0 dans cet exemple) et copier automatiquement tenseurs entre les appareils si nécessaire.

Limiter la croissance de la mémoire GPU

Par défaut, tensorflow cartes presque tous de la mémoire GPU de tous les GPU (sous réserve de CUDA_VISIBLE_DEVICES ) visibles au processus. Ceci est fait pour utiliser plus efficacement les ressources mémoire relativement précieuses du GPU sur les appareils en réduisant la fragmentation de la mémoire. Pour limiter tensorflow à un ensemble spécifique de processeurs graphiques, utilisez la tf.config.set_visible_devices méthode.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Restrict TensorFlow to only use the first GPU
  try:
    tf.config.set_visible_devices(gpus[0], 'GPU')
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPU")
  except RuntimeError as e:
    # Visible devices must be set before GPUs have been initialized
    print(e)
1 Physical GPUs, 1 Logical GPU

Dans certains cas, il est souhaitable que le processus n'alloue qu'un sous-ensemble de la mémoire disponible ou n'augmente l'utilisation de la mémoire que selon les besoins du processus. TensorFlow propose deux méthodes pour contrôler cela.

La première option consiste à transformer la croissance de la mémoire en appelant tf.config.experimental.set_memory_growth , qui tente d'allouer autant que la mémoire du GPU au besoin pour les allocations d'exécution: il commence l' allocation très peu de mémoire et que le programme soit lancé et plus de mémoire GPU est nécessaire, la région de mémoire GPU est étendue pour le processus TensorFlow. La mémoire n'est pas libérée car cela peut entraîner une fragmentation de la mémoire. Pour activer la croissance de la mémoire pour un GPU spécifique, utilisez le code suivant avant d'allouer des tenseurs ou d'exécuter des opérations.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  try:
    # Currently, memory growth needs to be the same across GPUs
    for gpu in gpus:
      tf.config.experimental.set_memory_growth(gpu, True)
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  except RuntimeError as e:
    # Memory growth must be set before GPUs have been initialized
    print(e)
Physical devices cannot be modified after being initialized

Une autre façon d'activer cette option est de définir la variable d' environnement TF_FORCE_GPU_ALLOW_GROWTH à true . Cette configuration est spécifique à la plate-forme.

La deuxième méthode consiste à configurer un dispositif de GPU virtuel avec tf.config.set_logical_device_configuration et définir une limite dure sur la mémoire totale à allouer à la GPU.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Restrict TensorFlow to only allocate 1GB of memory on the first GPU
  try:
    tf.config.set_logical_device_configuration(
        gpus[0],
        [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.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)
Virtual devices cannot be modified after being initialized

Ceci est utile si vous souhaitez vraiment limiter la quantité de mémoire GPU disponible pour le processus TensorFlow. Il s'agit d'une pratique courante pour le développement local lorsque le GPU est partagé avec d'autres applications telles qu'une interface graphique de poste de travail.

Utiliser un seul GPU sur un système multi-GPU

Si vous avez plus d'un GPU dans votre système, le GPU avec le plus petit ID sera sélectionné par défaut. Si vous souhaitez exécuter sur un autre GPU, vous devrez spécifier explicitement la préférence :

tf.debugging.set_log_device_placement(True)

try:
  # Specify an invalid GPU device
  with tf.device('/device:GPU:2'):
    a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
    b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
    c = tf.matmul(a, b)
except RuntimeError as e:
  print(e)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0

Si l'appareil que vous avez spécifié n'existe pas, vous obtiendrez un RuntimeError : .../device:GPU:2 unknown device .

Si vous souhaitez tensorflow choisir automatiquement un périphérique existant et pris en charge pour exécuter les opérations en cas spécifié on n'a pas existe, vous pouvez appeler tf.config.set_soft_device_placement(True) .

tf.config.set_soft_device_placement(True)
tf.debugging.set_log_device_placement(True)

# Creates some tensors
a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
c = tf.matmul(a, b)

print(c)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)

Utilisation de plusieurs GPU

Le développement pour plusieurs GPU permettra à un modèle d'évoluer avec les ressources supplémentaires. Si vous développez sur un système avec un seul GPU, vous pouvez simuler plusieurs GPU avec des périphériques virtuels. Cela permet de tester facilement les configurations multi-GPU sans nécessiter de ressources supplémentaires.

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Create 2 virtual GPUs with 1GB memory each
  try:
    tf.config.set_logical_device_configuration(
        gpus[0],
        [tf.config.LogicalDeviceConfiguration(memory_limit=1024),
         tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.list_logical_devices('GPU')
    print(len(gpus), "Physical GPU,", len(logical_gpus), "Logical GPUs")
  except RuntimeError as e:
    # Virtual devices must be set before GPUs have been initialized
    print(e)
Virtual devices cannot be modified after being initialized

Une fois il y a plusieurs processeurs graphiques logiques disponibles à l'exécution, vous pouvez utiliser les multiples processeurs graphiques avec tf.distribute.Strategy ou avec le placement manuel.

avec tf.distribute.Strategy

La meilleure pratique pour l' utilisation de plusieurs processeurs graphiques est d'utiliser tf.distribute.Strategy . Voici un exemple simple :

tf.debugging.set_log_device_placement(True)
gpus = tf.config.list_logical_devices('GPU')
strategy = tf.distribute.MirroredStrategy(gpus)
with strategy.scope():
  inputs = tf.keras.layers.Input(shape=(1,))
  predictions = tf.keras.layers.Dense(1)(inputs)
  model = tf.keras.models.Model(inputs=inputs, outputs=predictions)
  model.compile(loss='mse',
                optimizer=tf.keras.optimizers.SGD(learning_rate=0.2))
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op RandomUniform in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Sub in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Mul in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AddV2 in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Fill in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
INFO:tensorflow:Reduce to /job:localhost/replica:0/task:0/device:CPU:0 then broadcast to ('/job:localhost/replica:0/task:0/device:CPU:0',).
Executing op ReadVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Identity in device /job:localhost/replica:0/task:0/device:CPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op NoOp in device /job:localhost/replica:0/task:0/device:GPU:0

Ce programme se déroulera une copie de votre modèle sur chaque GPU, diviser les données d'entrée entre eux, également connu comme « le parallélisme de données ».

Pour plus d' informations sur les stratégies de distribution, consultez le guide ici .

Placement manuel

tf.distribute.Strategy fonctionne sous le capot en répliquant à travers les dispositifs de calcul. Vous pouvez implémenter manuellement la réplication en construisant votre modèle sur chaque GPU. Par exemple:

tf.debugging.set_log_device_placement(True)

gpus = tf.config.list_logical_devices('GPU')
if gpus:
  # Replicate your computation on multiple GPUs
  c = []
  for gpu in gpus:
    with tf.device(gpu.name):
      a = tf.constant([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
      b = tf.constant([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
      c.append(tf.matmul(a, b))

  with tf.device('/CPU:0'):
    matmul_sum = tf.add_n(c)

  print(matmul_sum)
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op _EagerConst in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
tf.Tensor(
[[22. 28.]
 [49. 64.]], shape=(2, 2), dtype=float32)