Formation distribuée avec TensorFlow

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

Aperçu

tf.distribute.Strategy est une API tensorflow pour distribuer la formation sur plusieurs processeurs graphiques, plusieurs machines ou PUT. À l'aide de cette API, vous pouvez distribuer vos modèles existants et votre code d'entraînement avec un minimum de modifications de code.

tf.distribute.Strategy a été conçu avec ces objectifs clés à l' esprit:

  • Facile à utiliser et prend en charge plusieurs segments d'utilisateurs, y compris les chercheurs, les ingénieurs en apprentissage automatique, etc.
  • Fournir de bonnes performances hors de la boîte.
  • Basculement facile entre les stratégies.

tf.distribute.Strategy peut être utilisé avec une API de haut niveau comme Keras , et peut également être utilisé pour distribuer des boucles de formation sur mesure (et, en général, tout calcul en utilisant tensorflow).

En tensorflow 2.x, vous pouvez exécuter vos programmes avec impatience, ou dans un graphique à l' aide tf.function . tf.distribute.Strategy entend soutenir ces deux modes d'exécution, mais fonctionne mieux avec tf.function . Le mode Désireuse est recommandé uniquement à des fins de débogage et non pris en charge pour tf.distribute.TPUStrategy . Bien que la formation soit au centre de ce guide, cette API peut également être utilisée pour distribuer l'évaluation et la prédiction sur différentes plateformes.

Vous pouvez utiliser tf.distribute.Strategy avec très peu de changements à votre code, car les composants sous - jacents de tensorflow ont été modifiés pour devenir stratégie consciente. Cela inclut les variables, les couches, les modèles, les optimiseurs, les métriques, les résumés et les points de contrôle.

Dans ce guide, vous découvrirez différents types de stratégies et comment vous pouvez les utiliser dans différentes situations. Pour savoir comment déboguer les problèmes de performance, voir le rendement GPU Optimize tensorflow guide.

# Import TensorFlow
import tensorflow as tf

Types de stratégies

tf.distribute.Strategy entend couvrir un certain nombre de cas d'utilisation le long des axes différents. Certaines de ces combinaisons sont actuellement prises en charge et d'autres seront ajoutées à l'avenir. Certains de ces axes sont :

  • Synchrone vs formation asynchrone: Ce sont deux façons communes de distribuer la formation avec le parallélisme de données. Dans la formation synchronisée, tous les travailleurs s'entraînent sur différentes tranches de données d'entrée en synchronisation et en agrégeant des gradients à chaque étape. Dans la formation asynchrone, tous les travailleurs s'entraînent indépendamment sur les données d'entrée et mettent à jour les variables de manière asynchrone. En règle générale, la formation de synchronisation est prise en charge via l'architecture de serveur de paramètres tout-réduction et asynchrone.
  • Plate - forme matérielle: Vous pouvez faire évoluer votre formation sur plusieurs processeurs graphiques sur une machine ou plusieurs machines dans un réseau (avec 0 ou plus processeurs graphiques chacun), ou sur le Cloud PUT.

Afin de prendre en charge ces cas d'utilisation, 6 stratégies sont disponibles. La section suivante explique lesquels d'entre eux sont pris en charge dans quels scénarios dans TensorFlow. Voici un aperçu rapide :

API de formation Stratégie en miroir TPUStratégie MultiWorkerMirroredStrategy Stratégie de stockage central ParamètreServeurStratégie
API Keras Prise en charge Prise en charge Prise en charge Accompagnement expérimental Accompagnement expérimental
Boucle d'entraînement personnalisée Prise en charge Prise en charge Prise en charge Accompagnement expérimental Accompagnement expérimental
API de l'estimateur Assistance limitée Non supporté Assistance limitée Assistance limitée Assistance limitée

Stratégie en miroir

tf.distribute.MirroredStrategy supports de formation synchronisme réparti sur plusieurs GPU sur une machine. Il crée une réplique par périphérique GPU. Chaque variable du modèle est reflétée sur toutes les répliques. Ensemble, ces variables forment une seule variable conceptuelle appelée MirroredVariable . Ces variables sont synchronisées les unes avec les autres en appliquant des mises à jour identiques.

Des algorithmes efficaces de réduction intégrale sont utilisés pour communiquer les mises à jour des variables entre les appareils. All-reduce agrège les tenseurs sur tous les appareils en les additionnant et les rend disponibles sur chaque appareil. C'est un algorithme fusionné qui est très efficace et peut réduire considérablement la surcharge de synchronisation. Il existe de nombreux algorithmes et implémentations tout-réduction disponibles, selon le type de communication disponible entre les appareils. Par défaut, il utilise la Bibliothèque de communication collective NVIDIA ( NCCL ) que la mise en œuvre tout réduire. Vous pouvez choisir parmi quelques autres options ou écrire la vôtre.

Voici la façon la plus simple de créer MirroredStrategy :

mirrored_strategy = tf.distribute.MirroredStrategy()
2021-08-21 01:24:44.677825: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:44.686081: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:44.687041: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:44.689423: I tensorflow/core/platform/cpu_feature_guard.cc:142] This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2 AVX512F FMA
To enable them in other operations, rebuild TensorFlow with the appropriate compiler flags.
2021-08-21 01:24:44.690022: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:44.690987: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:44.691896: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:45.284404: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:45.285446: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:45.286341: I tensorflow/stream_executor/cuda/cuda_gpu_executor.cc:937] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero
2021-08-21 01:24:45.287150: I tensorflow/core/common_runtime/gpu/gpu_device.cc:1510] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 14648 MB memory:  -> device: 0, name: Tesla V100-SXM2-16GB, pci bus id: 0000:00:05.0, compute capability: 7.0
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

Cela va créer un MirroredStrategy exemple, qui utilisera tous les processeurs graphiques qui sont visibles à tensorflow et NCCL, comme la communication multi-appareils.

Si vous souhaitez n'utiliser que certains des GPU sur votre machine, vous pouvez le faire comme ceci :

mirrored_strategy = tf.distribute.MirroredStrategy(devices=["/gpu:0", "/gpu:1"])
WARNING:tensorflow:Some requested devices in `tf.distribute.Strategy` are not visible to TensorFlow: /job:localhost/replica:0/task:0/device:GPU:0,/job:localhost/replica:0/task:0/device:GPU:1
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0', '/job:localhost/replica:0/task:0/device:GPU:1')

Si vous souhaitez passer outre la communication de l' appareil croix, vous pouvez le faire en utilisant le cross_device_ops argument en fournissant une instance de tf.distribute.CrossDeviceOps . À l' heure actuelle, tf.distribute.HierarchicalCopyAllReduce et tf.distribute.ReductionToOneDevice sont deux autres options que tf.distribute.NcclAllReduce , qui est la valeur par défaut.

mirrored_strategy = tf.distribute.MirroredStrategy(
    cross_device_ops=tf.distribute.HierarchicalCopyAllReduce())
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)

TPUStratégie

tf.distribute.TPUStrategy vous permet d' exécuter votre formation tensorflow sur les unités Tensor traitement (PUT). Les TPU sont des ASIC spécialisés de Google conçus pour accélérer considérablement les charges de travail d'apprentissage automatique. Ils sont disponibles sur Google Colab , le TPU recherche nuage et nuage TPU .

En termes d'architecture de formation distribuée, TPUStrategy est le même MirroredStrategy la formation des outils de distribution. PUT fournir leur propre mise en œuvre de l' efficacité tout réduire et d' autres opérations collectives sur plusieurs cœurs de TPU, qui sont utilisés dans TPUStrategy .

Voici comment vous instancierez TPUStrategy :

cluster_resolver = tf.distribute.cluster_resolver.TPUClusterResolver(
    tpu=tpu_address)
tf.config.experimental_connect_to_cluster(cluster_resolver)
tf.tpu.experimental.initialize_tpu_system(cluster_resolver)
tpu_strategy = tf.distribute.TPUStrategy(cluster_resolver)

Le TPUClusterResolver exemple aide à localiser le PUT. Dans Colab, vous n'avez pas besoin de lui spécifier d'arguments.

Si vous souhaitez l'utiliser pour les Cloud TPU :

  • Vous devez indiquer le nom de votre ressource en TPU dans le tpu argument.
  • Vous devez initialiser le système tpu explicitement au début du programme. Cela est nécessaire avant que les TPU puissent être utilisés pour le calcul. L'initialisation du système tpu efface également la mémoire TPU, il est donc important de terminer cette étape en premier afin d'éviter de perdre l'état.

MultiWorkerMirroredStrategy

tf.distribute.MultiWorkerMirroredStrategy est très similaire à MirroredStrategy . Il met en œuvre une formation distribuée synchrone sur plusieurs travailleurs, chacun avec potentiellement plusieurs GPU. Semblable à tf.distribute.MirroredStrategy , il crée des copies de toutes les variables du modèle sur chaque appareil à tous les travailleurs.

Voici la façon la plus simple de créer MultiWorkerMirroredStrategy :

strategy = tf.distribute.MultiWorkerMirroredStrategy()
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CommunicationImplementation.AUTO

MultiWorkerMirroredStrategy a deux implémentations de communications multi-appareils. CommunicationImplementation.RING est RPC à base et prend en charge les processeurs et processeurs graphiques. CommunicationImplementation.NCCL utilise NCCL et offre des performances l' état de l' art sur les processeurs graphiques , mais il ne prend pas en charge les processeurs. CollectiveCommunication.AUTO diffère le choix de tensorflow. Vous pouvez les spécifier de la manière suivante :

communication_options = tf.distribute.experimental.CommunicationOptions(
    implementation=tf.distribute.experimental.CommunicationImplementation.NCCL)
strategy = tf.distribute.MultiWorkerMirroredStrategy(
    communication_options=communication_options)
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled.
INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CommunicationImplementation.NCCL

L'une des principales différences pour lancer la formation multi-travailleurs, par rapport à la formation multi-GPU, est la configuration multi-travailleurs. La TF_CONFIG variable d'environnement est la manière standard tensorflow pour spécifier la configuration du cluster à chaque travailleur qui fait partie du groupe. En savoir plus sur la mise en place TF_CONFIG .

ParamètreServeurStratégie

La formation de serveur de paramètres est une méthode commune de données parallèles pour étendre la formation de modèle sur plusieurs machines. Un cluster de formation de serveur de paramètres se compose de travailleurs et de serveurs de paramètres. Les variables sont créées sur les serveurs de paramètres et elles sont lues et mises à jour par les travailleurs à chaque étape. Consultez la formation du serveur de paramètres tutoriel pour plus de détails.

Dans tensorflow 2, la formation de serveur de paramètres utilise une architecture à base de coordonnateur central via la tf.distribute.experimental.coordinator.ClusterCoordinator classe.

Dans cette mise en œuvre, les worker et parameter server tâches sont exécutées tf.distribute.Server s qui écoutent les tâches du coordinateur. Le coordinateur crée des ressources, répartit les tâches de formation, écrit des points de contrôle et gère les échecs des tâches.

Dans la programmation en cours d' exécution sur le coordinateur, vous utiliserez un ParameterServerStrategy objet pour définir une étape de formation et d' utiliser un ClusterCoordinator pour expédier les étapes de formation aux travailleurs à distance. Voici la façon la plus simple de les créer :

strategy = tf.distribute.experimental.ParameterServerStrategy(
    tf.distribute.cluster_resolver.TFConfigClusterResolver(),
    variable_partitioner=variable_partitioner)
coordinator = tf.distribute.experimental.coordinator.ClusterCoordinator(
    strategy)

Dans tensorflow 1, ParameterServerStrategy est disponible uniquement avec un estimateur par tf.compat.v1.distribute.experimental.ParameterServerStrategy symbole.

Stratégie de stockage central

tf.distribute.experimental.CentralStorageStrategy fait une formation synchrone aussi bien. Les variables ne sont pas mises en miroir, elles sont plutôt placées sur le CPU et les opérations sont répliquées sur tous les GPU locaux. S'il n'y a qu'un seul GPU, toutes les variables et opérations seront placées sur ce GPU.

Créer une instance de CentralStorageStrategy par:

central_storage_strategy = tf.distribute.experimental.CentralStorageStrategy()
INFO:tensorflow:ParameterServerStrategy (CentralStorageStrategy if you are using a single machine) with compute_devices = ['/job:localhost/replica:0/task:0/device:GPU:0'], variable_device = '/job:localhost/replica:0/task:0/device:GPU:0'

Cela va créer un CentralStorageStrategy exemple qui utilisera tous les processeurs graphiques visibles et CPU. La mise à jour des variables sur les réplicas sera agrégée avant d'être appliquée aux variables.

Autres stratégies

En plus des stratégies ci - dessus, il y a deux autres stratégies qui pourraient être utiles pour le prototypage et le débogage lors de l' utilisation tf.distribute API.

Stratégie par défaut

La stratégie par défaut est une stratégie de distribution qui est présente lorsqu'aucune stratégie de distribution explicite n'est dans la portée. Elle met en œuvre la tf.distribute.Strategy l' interface , mais est un pass-through et ne fournit aucune distribution réelle. Par exemple, strategy.run(fn) appellera simplement fn . Le code écrit à l'aide de cette stratégie doit se comporter exactement comme du code écrit sans aucune stratégie. Vous pouvez le considérer comme une stratégie « no-op ».

La stratégie par défaut est un singleton et on ne peut pas en créer plus d'instances. Il peut être obtenu en utilisant tf.distribute.get_strategy en dehors du champ d'application de toute stratégie explicite (la même API qui peut être utilisé pour obtenir la stratégie actuelle dans le champ d'application d' une stratégie explicite).

default_strategy = tf.distribute.get_strategy()

Cette stratégie a deux objectifs principaux :

  • Il permet d'écrire inconditionnellement du code de bibliothèque compatible avec la distribution. Par exemple, dans tf.optimizer s vous pouvez utiliser tf.distribute.get_strategy et utiliser cette stratégie pour réduire les gradients , il renvoie toujours un objet de stratégie sur laquelle vous pouvez appeler l' Strategy.reduce API.
# In optimizer or other library code
# Get currently active strategy
strategy = tf.distribute.get_strategy()
strategy.reduce("SUM", 1., axis=None)  # reduce some values
1.0
  • Semblable au code de bibliothèque, il peut être utilisé pour écrire des programmes d'utilisateurs finaux pour travailler avec et sans stratégie de distribution, sans nécessiter de logique conditionnelle. Voici un exemple d'extrait de code illustrant ceci :
if tf.config.list_physical_devices('GPU'):
  strategy = tf.distribute.MirroredStrategy()
else:  # Use the Default Strategy
  strategy = tf.distribute.get_strategy()

with strategy.scope():
  # Do something interesting
  print(tf.Variable(1.))
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)
MirroredVariable:{
  0: <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>
}

OneDeviceStrategy

tf.distribute.OneDeviceStrategy est une stratégie pour mettre toutes les variables et le calcul sur un périphérique spécifié unique.

strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")

Cette stratégie est distincte de la stratégie par défaut à plusieurs égards. Dans la stratégie par défaut, la logique de placement des variables reste inchangée par rapport à l'exécution de TensorFlow sans aucune stratégie de distribution. Mais lorsque vous utilisez OneDeviceStrategy , toutes les variables créées dans son champ d' application sont explicitement placés sur le périphérique spécifié. En outre, toutes les fonctions appelées par l' intermédiaire d' OneDeviceStrategy.run seront également placés sur le périphérique spécifié.

Les entrées distribuées via cette stratégie seront préchargées sur le périphérique spécifié. Dans la stratégie par défaut, il n'y a pas de distribution d'entrée.

Semblable à la stratégie par défaut, cette stratégie peut également être utilisée pour tester votre code avant de passer à d'autres stratégies qui sont réellement distribuées sur plusieurs appareils/machines. Cela exercera les mécanismes de la stratégie de distribution un peu plus que la stratégie par défaut, mais pas dans toute la mesure de l' utilisation, par exemple, MirroredStrategy ou TPUStrategy . Si vous voulez un code qui se comporte comme s'il n'y avait pas de stratégie, utilisez la stratégie par défaut.

Jusqu'à présent, vous avez vu les différentes stratégies disponibles et comment vous pouvez les instancier. Les prochaines sections montrent les différentes manières dont vous pouvez les utiliser pour distribuer votre formation.

En utilisant tf.distribute.Strategy avec tf.keras.Model.fit

tf.distribute.Strategy est intégré dans tf.keras , qui est la mise en œuvre de tensorflow de la spécification API Keras . tf.keras est une API de haut niveau pour les modèles de construction et de train. En intégrant dans tf.keras back - end, il est transparent pour vous de distribuer votre formation écrite dans le cadre de la formation Keras utilisant Model.fit .

Voici ce que vous devez modifier dans votre code :

  1. Créer une instance de la appropriée tf.distribute.Strategy .
  2. Déplacer la création du modèle Keras, optimiseur et des mesures à l' intérieur strategy.scope .

Les stratégies de distribution TensorFlow prennent en charge tous les types de modèles Keras : séquentiels, fonctionnels et sous-classés.

Voici un extrait de code pour le faire pour un modèle Keras très simple avec une couche dense :

mirrored_strategy = tf.distribute.MirroredStrategy()

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])

model.compile(loss='mse', optimizer='sgd')
INFO:tensorflow:Using MirroredStrategy with devices ('/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',).
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',).
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',).
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',).

Cet exemple utilise MirroredStrategy , de sorte que vous pouvez exécuter sur une machine avec plusieurs processeurs graphiques. strategy.scope() indique Keras quelle stratégie à utiliser pour distribuer la formation. La création de modèles/optimiseurs/métriques à l'intérieur de cette portée vous permet de créer des variables distribuées au lieu de variables régulières. Une fois celui-ci configuré, vous pouvez adapter votre modèle comme vous le feriez normalement. MirroredStrategy prend soin de répliquer la formation du modèle sur les processeurs graphiques disponibles, l' agrégation des gradients, et plus encore.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(10)
model.fit(dataset, epochs=2)
model.evaluate(dataset)
Epoch 1/2
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',).
2021-08-21 01:24:46.237677: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:695] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}

2021-08-21 01:24:46.271153: I tensorflow/compiler/mlir/mlir_graph_optimization_pass.cc:185] None of the MLIR Optimization Passes are enabled (registered 2)
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',).
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',).
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',).
10/10 [==============================] - 3s 2ms/step - loss: 0.0086
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',).
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',).
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0038
2021-08-21 01:24:49.147347: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:695] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}
10/10 [==============================] - 1s 2ms/step - loss: 0.0024
0.002372059039771557

Voici une tf.data.Dataset offre la formation et l' entrée eval. Vous pouvez également utiliser des tableaux NumPy :

import numpy as np

inputs, targets = np.ones((100, 1)), np.ones((100, 1))
model.fit(inputs, targets, epochs=2, batch_size=10)
Epoch 1/2
10/10 [==============================] - 0s 2ms/step - loss: 0.0017
Epoch 2/2
10/10 [==============================] - 0s 2ms/step - loss: 7.4622e-04
2021-08-21 01:24:50.486957: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:695] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Did not find a shardable source, walked to a node which is not a dataset: name: "FlatMapDataset/_9"
op: "FlatMapDataset"
input: "PrefetchDataset/_8"
attr {
  key: "Targuments"
  value {
    list {
    }
  }
}
attr {
  key: "f"
  value {
    func {
      name: "__inference_Dataset_flat_map_slice_batch_indices_997"
    }
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 10
        }
      }
    }
  }
}
attr {
  key: "output_types"
  value {
    list {
      type: DT_INT64
    }
  }
}
. Consider either turning off auto-sharding or switching the auto_shard_policy to DATA to shard this dataset. You can do this by creating a new `tf.data.Options()` object then setting `options.experimental_distribute.auto_shard_policy = AutoShardPolicy.DATA` before applying the options object to the dataset via `dataset.with_options(options)`.
<keras.callbacks.History at 0x7f12401ede10>

Dans les deux cas avec l' Dataset de Dataset ou Numpy-chaque lot de l'entrée donnée est divisée également entre les multiples répliques. Par exemple, si vous utilisez le MirroredStrategy avec 2 processeurs graphiques, chaque lot de taille 10 va se répartir entre les 2 GPUs, chacune recevant 5 exemples d'entrée dans chaque étape. Chaque époque s'entraînera ensuite plus rapidement à mesure que vous ajouterez plus de GPU. En règle générale, vous souhaiterez augmenter la taille de votre lot à mesure que vous ajoutez plus d'accélérateurs, afin d'utiliser efficacement la puissance de calcul supplémentaire. Vous devrez également réajuster votre taux d'apprentissage, selon le modèle. Vous pouvez utiliser strategy.num_replicas_in_sync pour obtenir le nombre de répliques.

# Compute a global batch size using a number of replicas.
BATCH_SIZE_PER_REPLICA = 5
global_batch_size = (BATCH_SIZE_PER_REPLICA *
                     mirrored_strategy.num_replicas_in_sync)
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100)
dataset = dataset.batch(global_batch_size)

LEARNING_RATES_BY_BATCH_SIZE = {5: 0.1, 10: 0.15}
learning_rate = LEARNING_RATES_BY_BATCH_SIZE[global_batch_size]

Qu'est-ce qui est pris en charge maintenant ?

API de formation Stratégie en miroir TPUStratégie MultiWorkerMirroredStrategy ParamètreServeurStratégie Stratégie de stockage central
API Keras Prise en charge Prise en charge Prise en charge Accompagnement expérimental Accompagnement expérimental

Exemples et tutoriels

Voici une liste de tutoriels et d'exemples illustrant l'intégration de bout en bout ci-dessus avec Keras :

  1. Tutoriel pour former MNIST avec MirroredStrategy .
  2. Tutoriel pour former MNIST en utilisant MultiWorkerMirroredStrategy .
  3. Guide sur MNIST de formation à l' aide TPUStrategy .
  4. Tutoriel pour la formation de serveur de paramètres dans tensorflow 2 avec ParameterServerStrategy .
  5. Tensorflow Modèle jardin repository contenant des collections de modèles l' état de l'art mis en œuvre en utilisant diverses stratégies.

En utilisant tf.distribute.Strategy avec des boucles de formation sur mesure

Comme vous l' avez vu, en utilisant tf.distribute.Strategy avec Keras model.fit il faut changer seulement quelques lignes de votre code. Avec un peu plus d' effort, vous pouvez également utiliser tf.distribute.Strategy avec des boucles de formation sur mesure.

Si vous avez besoin de plus de flexibilité et de contrôle sur vos boucles d'entraînement qu'avec Estimator ou Keras, vous pouvez écrire des boucles d'entraînement personnalisées. Par exemple, lorsque vous utilisez un GAN, vous souhaiterez peut-être effectuer un nombre différent de pas de générateur ou de discriminateur à chaque tour. De même, les cadres de haut niveau ne sont pas très adaptés à la formation d'Apprentissage par Renforcement.

Les tf.distribute.Strategy classes fournissent un ensemble de base des méthodes pour soutenir les boucles de formation sur mesure. Leur utilisation peut nécessiter une restructuration mineure du code au départ, mais une fois cela fait, vous devriez pouvoir basculer entre les GPU, les TPU et plusieurs machines simplement en changeant l'instance de stratégie.

Ici, vous verrez un bref extrait illustrant ce cas d'utilisation pour un exemple de formation simple utilisant le même modèle Keras qu'auparavant.

Tout d'abord, créez le modèle et l'optimiseur dans le cadre de la stratégie. Cela garantit que toutes les variables créées avec le modèle et l'optimiseur sont des variables en miroir.

with mirrored_strategy.scope():
  model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
  optimizer = tf.keras.optimizers.SGD()

Ensuite, créez l'ensemble de données d'entrée et appelez tf.distribute.Strategy.experimental_distribute_dataset pour distribuer l'ensemble de données basé sur la stratégie.

dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(
    global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)
2021-08-21 01:24:50.715370: W tensorflow/core/grappler/optimizers/data/auto_shard.cc:695] AUTO sharding policy will apply DATA sharding policy as it failed to apply FILE sharding policy because of the following reason: Found an unshardable source dataset: name: "TensorDataset/_2"
op: "TensorDataset"
input: "Placeholder/_0"
input: "Placeholder/_1"
attr {
  key: "Toutput_types"
  value {
    list {
      type: DT_FLOAT
      type: DT_FLOAT
    }
  }
}
attr {
  key: "output_shapes"
  value {
    list {
      shape {
        dim {
          size: 1
        }
      }
      shape {
        dim {
          size: 1
        }
      }
    }
  }
}

Ensuite, définissez une étape de la formation. Utilisez tf.GradientTape aux gradients et optimiseur de calcul à appliquer ces gradients de mettre à jour les variables de votre modèle. Pour distribuer cette étape de formation, mettre en fonction train_step et le transmettre à tf.distrbute.Strategy.run ainsi que les entrées de jeu de données que vous avez obtenu du dist_dataset créé avant:

loss_object = tf.keras.losses.BinaryCrossentropy(
  from_logits=True,
  reduction=tf.keras.losses.Reduction.NONE)

def compute_loss(labels, predictions):
  per_example_loss = loss_object(labels, predictions)
  return tf.nn.compute_average_loss(per_example_loss, global_batch_size=global_batch_size)

def train_step(inputs):
  features, labels = inputs

  with tf.GradientTape() as tape:
    predictions = model(features, training=True)
    loss = compute_loss(labels, predictions)

  gradients = tape.gradient(loss, model.trainable_variables)
  optimizer.apply_gradients(zip(gradients, model.trainable_variables))
  return loss

@tf.function
def distributed_train_step(dist_inputs):
  per_replica_losses = mirrored_strategy.run(train_step, args=(dist_inputs,))
  return mirrored_strategy.reduce(tf.distribute.ReduceOp.SUM, per_replica_losses,
                         axis=None)

Quelques autres choses à noter dans le code ci-dessus :

  1. Vous avez utilisé tf.nn.compute_average_loss pour calculer la perte. tf.nn.compute_average_loss résume le par exemple la perte et divise la somme par le global_batch_size. Ceci est important car plus tard , après les gradients sont calculés sur chaque réplique, ils sont regroupés dans les répliques en les additionnant.
  2. Vous avez également utilisé le tf.distribute.Strategy.reduce API pour agréger les résultats retournés par tf.distribute.Strategy.run . tf.distribute.Strategy.run renvoie des résultats de chaque réplique locale dans la stratégie, et il y a plusieurs façons de consommer ce résultat. Vous pouvez reduce les pour obtenir une valeur agrégée. Vous pouvez également faire tf.distribute.Strategy.experimental_local_results pour obtenir la liste des valeurs contenues dans le résultat, une par réplique locale.
  3. Lorsque vous appelez apply_gradients dans un champ de la stratégie de distribution, son comportement est modifié. Plus précisément, avant d'appliquer des gradients sur chaque instance parallèle pendant l'entraînement synchrone, il effectue une somme sur toutes les répliques des gradients.

Enfin, une fois que vous avez défini l'étape de formation, vous pouvez itérer sur dist_dataset et exécuter la formation dans une boucle:

for dist_inputs in dist_dataset:
  print(distributed_train_step(dist_inputs))
tf.Tensor(1.3084135, shape=(), dtype=float32)
tf.Tensor(1.2977839, shape=(), dtype=float32)
tf.Tensor(1.2872384, shape=(), dtype=float32)
tf.Tensor(1.2767767, shape=(), dtype=float32)
tf.Tensor(1.2663989, shape=(), dtype=float32)
tf.Tensor(1.256105, shape=(), dtype=float32)
tf.Tensor(1.2458944, shape=(), dtype=float32)
tf.Tensor(1.2357674, shape=(), dtype=float32)
tf.Tensor(1.2257235, shape=(), dtype=float32)
tf.Tensor(1.2157627, shape=(), dtype=float32)
tf.Tensor(1.2058848, shape=(), dtype=float32)
tf.Tensor(1.1960893, shape=(), dtype=float32)
tf.Tensor(1.1863762, shape=(), dtype=float32)
tf.Tensor(1.1767453, shape=(), dtype=float32)
tf.Tensor(1.1671963, shape=(), dtype=float32)
tf.Tensor(1.1577287, shape=(), dtype=float32)
tf.Tensor(1.1483426, shape=(), dtype=float32)
tf.Tensor(1.1390375, shape=(), dtype=float32)
tf.Tensor(1.1298131, shape=(), dtype=float32)
tf.Tensor(1.1206692, shape=(), dtype=float32)

Dans l'exemple ci - dessus, vous itéré la dist_dataset de contribuer à votre formation. Vous êtes également fourni avec le tf.distribute.Strategy.make_experimental_numpy_dataset pour soutenir les entrées numpy. Vous pouvez utiliser cette API pour créer un ensemble de données avant d' appeler tf.distribute.Strategy.experimental_distribute_dataset .

Une autre façon d'itérer sur vos données consiste à utiliser explicitement des itérateurs. Vous pouvez effectuer cette opération lorsque vous souhaitez exécuter un nombre donné d'étapes au lieu d'itérer sur l'ensemble de données. Ce qui précède itération serait maintenant modifié pour d' abord créer un itérateur puis appeler explicitement à next sur elle pour obtenir les données d'entrée.

iterator = iter(dist_dataset)
for _ in range(10):
  print(distributed_train_step(next(iterator)))
tf.Tensor(1.1116053, shape=(), dtype=float32)
tf.Tensor(1.1026212, shape=(), dtype=float32)
tf.Tensor(1.0937165, shape=(), dtype=float32)
tf.Tensor(1.0848908, shape=(), dtype=float32)
tf.Tensor(1.0761441, shape=(), dtype=float32)
tf.Tensor(1.0674756, shape=(), dtype=float32)
tf.Tensor(1.0588851, shape=(), dtype=float32)
tf.Tensor(1.0503721, shape=(), dtype=float32)
tf.Tensor(1.0419363, shape=(), dtype=float32)
tf.Tensor(1.0335773, shape=(), dtype=float32)

Cette garantie couvre le cas le plus simple d'utiliser tf.distribute.Strategy API pour distribuer des boucles de formation personnalisés.

Qu'est-ce qui est pris en charge maintenant ?

API de formation Stratégie en miroir TPUStratégie MultiWorkerMirroredStrategy ParamètreServeurStratégie Stratégie de stockage central
Boucle d'entraînement personnalisée Prise en charge Prise en charge Prise en charge Accompagnement expérimental Accompagnement expérimental

Exemples et tutoriels

Voici quelques exemples d'utilisation de la stratégie de distribution avec des boucles d'entraînement personnalisées :

  1. Tutoriel pour former MNIST en utilisant MirroredStrategy .
  2. Guide sur MNIST de formation à l' aide TPUStrategy .
  3. Tensorflow Modèle jardin repository contenant des collections de modèles l' état de l'art mis en œuvre en utilisant diverses stratégies.

Autres sujets

Cette section couvre certains sujets qui sont pertinents pour plusieurs cas d'utilisation.

Configuration de la variable d'environnement TF_CONFIG

Pour la formation multi-travailleurs, comme mentionné précédemment, vous devez configurer la TF_CONFIG variable d'environnement pour chaque binaire en cours d' exécution dans votre cluster. La TF_CONFIG variable d'environnement est une chaîne JSON qui précise les tâches constituent un cluster, leurs adresses et le rôle de chaque tâche dans le cluster. Le tensorflow/ecosystem repo fournit un modèle Kubernetes, qui met en place TF_CONFIG pour vos tâches de formation.

Il y a deux composantes de TF_CONFIG : un cluster et une tâche.

  • Un cluster fournit des informations sur le cluster de formation, qui est un dict composé de différents types d'emplois tels que les travailleurs. Dans la formation multi-travailleurs, il y a généralement un travailleur qui assume un peu plus de responsabilités, comme l'enregistrement du point de contrôle et la rédaction d'un fichier récapitulatif pour TensorBoard, en plus de ce que fait un travailleur régulier. Ce travailleur est considéré comme travailleur « chef », et il est d' usage que le travailleur avec l' indice 0 est nommé chef travailleur (en fait , c'est de savoir comment tf.distribute.Strategy est mis en œuvre).
  • Une tâche, quant à elle, fournit des informations sur la tâche en cours. Le premier cluster de composants est le même pour tous les travailleurs, et la deuxième tâche de composant est différente pour chaque travailleur et spécifie le type et l'index de ce travailleur.

Un exemple de TF_CONFIG est:

os.environ["TF_CONFIG"] = json.dumps({
    "cluster": {
        "worker": ["host1:port", "host2:port", "host3:port"],
        "ps": ["host4:port", "host5:port"]
    },
   "task": {"type": "worker", "index": 1}
})

Cette TF_CONFIG précise qu'il ya trois travailleurs et deux "ps" tâches dans le "cluster" en même temps que leurs hôtes et les ports. La "task" partie précise le rôle de la tâche en cours dans le "cluster" -worker 1 (le deuxième travailleur). Rôles valides dans un cluster sont "chief" , "worker" , "ps" et "evaluator" . Il ne devrait pas "ps" travail , sauf lors de l' utilisation tf.distribute.experimental.ParameterServerStrategy .

Et après?

tf.distribute.Strategy est activement en cours de développement. Essayez et vos commentaires en utilisant les questions GitHub .