Réserve cette date! Google I / O revient du 18 au 20 mai S'inscrire maintenant
Cette page a été traduite par l'API Cloud Translation.
Switch to English

Utilisez un GPU

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

Le code TensorFlow et les modèles tf.keras s'exécuteront de manière transparente sur un seul GPU sans qu'aucune modification de code ne soit requise.

Le moyen le plus simple de s'exécuter sur plusieurs GPU, sur une ou plusieurs machines, consiste à utiliser des stratégies de distribution .

Ce guide est destiné aux utilisateurs qui ont essayé ces approches et ont constaté qu'ils avaient 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 performances pour les scénarios mono et multi-GPU, consultez le guide Optimiser les performances du GPU TensorFlow .

Installer

Assurez-vous que la dernière version gpu de TensorFlow est installée.

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

Aperçu

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

  • "/device:CPU:0" : la CPU de votre machine.
  • "/GPU:0" : notation abrégée du premier GPU de votre machine visible par TensorFlow.
  • "/job:localhost/replica:0/task:0/device:GPU:1" : nom complet du deuxième GPU de votre machine visible par TensorFlow.

Si une opération TensorFlow a à la fois des implémentations CPU et GPU, par défaut, les périphériques GPU auront la priorité lorsque l'opération est affectée à un périphérique. Par exemple, tf.matmul a à la fois des noyaux CPU et GPU. Sur un système avec des périphériques CPU:0 et GPU:0 , le périphérique GPU:0 sera sélectionné pour exécuter tf.matmul moins que vous ne tf.matmul explicitement de l'exécuter sur un autre périphérique.

Emplacement du périphérique de journalisation

Pour savoir à quels périphériques vos opérations et tenseurs sont affectés, mettez tf.debugging.set_log_device_placement(True) comme première instruction de votre programme. L'activation de la journalisation du placement de périphérique 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 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 que l'opération MatMul été exécutée sur le GPU:0 .

Placement manuel de l'appareil

Si vous souhaitez qu'une opération particulière s'exécute sur un appareil 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 d'appareil, et toutes les opérations dans ce contexte s'exécuteront 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 assignés à la CPU:0 . Puisqu'un périphérique n'a pas été explicitement spécifié pour l'opération MatMul , le runtime TensorFlow en choisira un en fonction de l'opération et des périphériques disponibles ( GPU:0 dans cet exemple) et copiera automatiquement les tenseurs entre les périphériques si nécessaire.

Limiter la croissance de la mémoire GPU

Par défaut, TensorFlow mappe presque toute la mémoire GPU de tous les GPU (sous réserve de CUDA_VISIBLE_DEVICES ) visibles par le processus. Ceci est fait pour utiliser plus efficacement les ressources de mémoire GPU relativement précieuses sur les appareils en réduisant la fragmentation de la mémoire. Pour limiter TensorFlow à un ensemble spécifique de GPU, nous utilisons la méthode tf.config.experimental.set_visible_devices .

gpus = tf.config.list_physical_devices('GPU')
if gpus:
  # Restrict TensorFlow to only use the first GPU
  try:
    tf.config.experimental.set_visible_devices(gpus[0], 'GPU')
    logical_gpus = tf.config.experimental.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)
2 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 à activer la croissance de la mémoire en appelant tf.config.experimental.set_memory_growth , qui tente d'allouer uniquement autant de mémoire GPU que nécessaire pour les allocations d'exécution: cela commence par allouer très peu de mémoire, et lorsque le programme est exécuté plus de mémoire GPU est nécessaire, nous étendons la région de mémoire GPU allouée au processus TensorFlow. Notez que nous ne libérons pas de mémoire, 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.experimental.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)
2 Physical GPUs, 2 Logical GPUs

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

La deuxième méthode consiste à configurer un périphérique GPU virtuel avec tf.config.experimental.set_virtual_device_configuration et à définir une limite tf.config.experimental.set_virtual_device_configuration sur la mémoire totale à allouer sur le 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.experimental.set_virtual_device_configuration(
        gpus[0],
        [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.experimental.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)
2 Physical GPUs, 2 Logical GPUs

Ceci est utile si vous souhaitez vraiment lier 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.

Utilisation d'un seul GPU sur un système multi-GPU

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

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)
/job:localhost/replica:0/task:0/device:GPU:2 unknown device.

Si le périphérique que vous avez spécifié n'existe pas, vous obtiendrez un RuntimeError : .../device:GPU:2 unknown device .

Si vous souhaitez que TensorFlow choisisse automatiquement un périphérique existant et pris en charge pour exécuter les opérations au cas où celui spécifié n'existerait pas, 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 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, nous pouvons simuler plusieurs GPU avec des appareils 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.experimental.set_virtual_device_configuration(
        gpus[0],
        [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024),
         tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])
    logical_gpus = tf.config.experimental.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)
2 Physical GPU, 3 Logical GPUs

Une fois que nous avons plusieurs GPU logiques disponibles pour le runtime, nous pouvons utiliser les multiples GPU avec tf.distribute.Strategy ou avec un placement manuel.

Avec tf.distribute.Strategy

La meilleure pratique pour utiliser plusieurs GPU consiste à utiliser tf.distribute.Strategy . Voici un exemple simple:

tf.debugging.set_log_device_placement(True)

strategy = tf.distribute.MirroredStrategy()
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 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 Add 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 VarIsInitializedOp in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op LogicalNot in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op Assert 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 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:1
Executing op VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op VarIsInitializedOp in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op LogicalNot in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op Assert in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op AssignVariableOp in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op Reshape 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 VarHandleOp in device /job:localhost/replica:0/task:0/device:GPU:1

Ce programme exécutera une copie de votre modèle sur chaque GPU, en divisant les données d'entrée entre eux, également connu sous le nom de « parallélisme des 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 le calcul sur les appareils. Vous pouvez implémenter manuellement la réplication en construisant votre modèle sur chaque GPU. Par example:

tf.debugging.set_log_device_placement(True)

gpus = tf.config.experimental.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 MatMul in device /job:localhost/replica:0/task:0/device:GPU:0
Executing op MatMul in device /job:localhost/replica:0/task:0/device:GPU:1
Executing op AddN in device /job:localhost/replica:0/task:0/device:CPU:0
tf.Tensor(
[[ 44.  56.]
 [ 98. 128.]], shape=(2, 2), dtype=float32)