![]() | ![]() | ![]() | ![]() |
Visión general
tf.distribute.Strategy
es una API de TensorFlow para distribuir el entrenamiento en múltiples GPU, múltiples máquinas o TPU. Con esta API, puede distribuir sus modelos existentes y el código de entrenamiento con cambios mínimos en el código.
tf.distribute.Strategy
ha sido diseñado con estos objetivos clave en mente:
- Fácil de usar y compatible con múltiples segmentos de usuarios, incluidos investigadores, ingenieros de ML, etc.
- Proporciona un buen rendimiento desde el primer momento.
- Fácil cambio entre estrategias.
tf.distribute.Strategy
se puede usar con una API de alto nivel como Keras , y también se puede usar para distribuir ciclos de entrenamiento personalizados (y, en general, cualquier cálculo usando TensorFlow).
En TensorFlow 2.x, puede ejecutar sus programas con entusiasmo o en un gráfico usando tf.function
. tf.distribute.Strategy
intenta admitir ambos modos de ejecución, pero funciona mejor con tf.function
. El modo ansioso solo se recomienda para fines de depuración y no es compatible con TPUStrategy
. Si bien la capacitación es el tema central de esta guía, esta API también se puede utilizar para distribuir evaluaciones y predicciones en diferentes plataformas.
Puede usar tf.distribute.Strategy
con muy pocos cambios en su código, porque hemos cambiado los componentes subyacentes de TensorFlow para que sean conscientes de la estrategia. Esto incluye variables, capas, modelos, optimizadores, métricas, resúmenes y puntos de control.
En esta guía, explicamos varios tipos de estrategias y cómo puede usarlas en diferentes situaciones. Para obtener información sobre cómo depurar problemas de rendimiento, consulte la guía Optimizar el rendimiento de la GPU de TensorFlow .
# Import TensorFlow
import tensorflow as tf
Tipos de estrategias
tf.distribute.Strategy
pretende cubrir una serie de casos de uso a lo largo de diferentes ejes. Algunas de estas combinaciones son compatibles actualmente y otras se agregarán en el futuro. Algunos de estos ejes son:
- Entrenamiento síncrono vs asincrónico: estas son dos formas comunes de distribuir el entrenamiento con paralelismo de datos. En el entrenamiento sincronizado, todos los trabajadores entrenan en diferentes segmentos de datos de entrada sincronizados y agregando gradientes en cada paso. En el entrenamiento asincrónico, todos los trabajadores se entrenan de forma independiente sobre los datos de entrada y actualizan las variables de forma asincrónica. Normalmente, el entrenamiento de sincronización se admite a través de all-reduce y async a través de la arquitectura del servidor de parámetros.
- Plataforma de hardware: es posible que desee escalar su entrenamiento a varias GPU en una máquina, o varias máquinas en una red (con 0 o más GPU cada una), o en Cloud TPU.
Para respaldar estos casos de uso, hay seis estrategias disponibles. La siguiente sección explica cuáles de estos son compatibles en qué escenarios en TF. Aquí hay una descripción general rápida:
API de entrenamiento | EspejoEstrategia | TPUStrategy | MultiWorkerMirroredStrategy | CentralStorageStrategy | ParameterServerStrategy |
---|---|---|---|---|---|
API de Keras | Soportado | Soportado | Soporte experimental | Soporte experimental | Publicación planificada apoyada 2.3 |
Bucle de entrenamiento personalizado | Soportado | Soportado | Soporte experimental | Soporte experimental | Publicación planificada compatible 2.3 |
API de estimador | Soporte limitado | No soportado | Soporte limitado | Soporte limitado | Soporte limitado |
EspejoEstrategia
tf.distribute.MirroredStrategy
admite el entrenamiento distribuido sincrónico en varias GPU en una máquina. Crea una réplica por dispositivo GPU. Cada variable del modelo se refleja en todas las réplicas. Juntas, estas variables forman una única variable conceptual llamada MirroredVariable
. Estas variables se mantienen sincronizadas entre sí mediante la aplicación de actualizaciones idénticas.
Se utilizan algoritmos eficientes de reducción total para comunicar las actualizaciones de variables entre los dispositivos. All-reduce agrega tensores en todos los dispositivos agregándolos y los pone a disposición en cada dispositivo. Es un algoritmo fusionado que es muy eficiente y puede reducir significativamente la sobrecarga de sincronización. Hay muchos algoritmos e implementaciones de reducción total disponibles, según el tipo de comunicación disponible entre dispositivos. De forma predeterminada, utiliza NVIDIA NCCL como la implementación de reducción total. Puede elegir entre algunas otras opciones o escribir la suya propia.
Esta es la forma más sencilla de crear MirroredStrategy
:
mirrored_strategy = tf.distribute.MirroredStrategy()
INFO:tensorflow:Using MirroredStrategy with devices ('/job:localhost/replica:0/task:0/device:GPU:0',)
Esto creará una instancia de MirroredStrategy
que usará todas las GPU que son visibles para TensorFlow y usará NCCL como comunicación entre dispositivos.
Si desea utilizar solo algunas de las GPU en su máquina, puede hacerlo así:
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:1,/job:localhost/replica:0/task:0/device:GPU:0 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 desea anular la comunicación entre dispositivos, puede hacerlo utilizando el argumento cross_device_ops
proporcionando una instancia de tf.distribute.CrossDeviceOps
. Actualmente, tf.distribute.HierarchicalCopyAllReduce
y tf.distribute.ReductionToOneDevice
son dos opciones distintas de tf.distribute.NcclAllReduce
que es la predeterminada.
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',)
TPUStrategy
tf.distribute.TPUStrategy
te permite ejecutar tu entrenamiento de TensorFlow en unidades de procesamiento de tensor (TPU). Los TPU son ASIC especializados de Google diseñados para acelerar drásticamente las cargas de trabajo de aprendizaje automático. Están disponibles en Google Colab, TensorFlow Research Cloud y Cloud TPU .
En términos de arquitectura de entrenamiento distribuido, TPUStrategy
es la misma MirroredStrategy
: implementa entrenamiento distribuido sincrónico. Las TPU proporcionan su propia implementación de operaciones colectivas eficientes de reducción total y otras en varios núcleos de TPU, que se utilizan en TPUStrategy
.
Así es como podría crear TPUStrategy
instancia de 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)
La instancia de TPUClusterResolver
ayuda a localizar las TPU. En Colab, no es necesario que le especifiques ningún argumento.
Si desea usar esto para Cloud TPU:
- Debes especificar el nombre de tu recurso de TPU en el argumento
tpu
. - Debe inicializar el sistema tpu explícitamente al inicio del programa. Esto es necesario antes de que las TPU se puedan utilizar para el cálculo. La inicialización del sistema tpu también borra la memoria de la TPU, por lo que es importante completar este paso primero para evitar perder el estado.
MultiWorkerMirroredStrategy
tf.distribute.MultiWorkerMirroredStrategy
es muy similar a MirroredStrategy
. Implementa entrenamiento distribuido sincrónico entre múltiples trabajadores, cada uno con potencialmente múltiples GPU. Similar a tf.distribute.MirroredStrategy
, crea copias de todas las variables en el modelo en cada dispositivo en todos los trabajadores.
Esta es la forma más sencilla de crear MultiWorkerMirroredStrategy
:
strategy = tf.distribute.MultiWorkerMirroredStrategy()
WARNING:tensorflow:Collective ops is not configured at program startup. Some performance features may not be enabled. INFO:tensorflow:Using MirroredStrategy with devices ('/device:GPU:0',) INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CommunicationImplementation.AUTO
MultiWorkerMirroredStrategy
tiene dos implementaciones para comunicaciones entre dispositivos. CommunicationImplementation.RING
está basado en RPC y es compatible con CPU y GPU. CommunicationImplementation.NCCL
utiliza NCCL de Nvidia y proporciona el rendimiento más avanzado en GPU, pero no es compatible con CPU. CollectiveCommunication.AUTO
cede la elección a Tensorflow. Puede especificarlos de la siguiente manera:
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:Using MirroredStrategy with devices ('/device:GPU:0',) INFO:tensorflow:Single-worker MultiWorkerMirroredStrategy with local_devices = ('/device:GPU:0',), communication = CommunicationImplementation.NCCL
Una de las diferencias clave para poner en marcha la formación de varios trabajadores, en comparación con la formación de varias GPU, es la configuración de varios trabajadores. La variable de entorno TF_CONFIG
es la forma estándar en TensorFlow de especificar la configuración del clúster para cada trabajador que forma parte del clúster. Obtenga más información sobre cómo configurar TF_CONFIG .
ParameterServerStrategy
El entrenamiento del servidor de parámetros es un método común de datos paralelos para escalar el entrenamiento del modelo en varias máquinas. Un clúster de formación del servidor de parámetros consta de trabajadores y servidores de parámetros. Las variables se crean en servidores de parámetros y los trabajadores las leen y actualizan en cada paso. Consulte el tutorial de formación del servidor de parámetros para obtener más detalles.
El entrenamiento del servidor de parámetros de TensorFlow 2 usa una arquitectura basada en un coordinador central a través de la clase tf.distribute.experimental.coordinator.ClusterCoordinator
.
En esta implementación, las tareas del parameter server
worker
y de parameter server
ejecutan tf.distribute.Server
s que escuchan las tareas del coordinador. El coordinador crea recursos, distribuye tareas de capacitación, escribe puntos de control y se ocupa de las fallas de tareas.
En la programación que se ejecuta en el coordinador, usará un objeto ParameterServerStrategy
para definir un paso de entrenamiento y usará un ClusterCoordinator
para enviar pasos de entrenamiento a trabajadores remotos. Esta es la forma más sencilla de crearlos:
strategy = tf.distribute.experimental.ParameterServerStrategy(
tf.distribute.cluster_resolver.TFConfigClusterResolver(),
variable_partitioner=variable_partitioner)
coordinator = tf.distribute.experimental.coordinator.ClusterCoordinator(
strategy)
Tenga en cuenta que deberá configurar la variable de entorno TF_CONFIG si utiliza TFConfigClusterResolver
. Es similar a TF_CONFIG en MultiWorkerMirroredStrategy
pero tiene advertencias adicionales.
En TF 1, ParameterServerStrategy
está disponible solo con estimador a través del símbolo tf.compat.v1.distribute.experimental.ParameterServerStrategy
.
CentralStorageStrategy
tf.distribute.experimental.CentralStorageStrategy
realiza entrenamiento sincrónico. Las variables no se reflejan, sino que se colocan en la CPU y las operaciones se replican en todas las GPU locales. Si solo hay una GPU, todas las variables y operaciones se colocarán en esa GPU.
Cree una instancia de CentralStorageStrategy
mediante:
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'
Esto creará una instancia de CentralStorageStrategy
que utilizará todas las GPU y CPU visibles. La actualización de las variables en las réplicas se agregará antes de aplicarse a las variables.
Otras estrategias
Además de las estrategias anteriores, existen otras dos estrategias que pueden resultar útiles para la creación de prototipos y la depuración cuando se utilizan tf.distribute
API de tf.distribute
.
Estrategia predeterminada
La estrategia predeterminada es una estrategia de distribución que está presente cuando no se incluye una estrategia de distribución explícita. Implementa la interfaz tf.distribute.Strategy
pero es un paso a través y no proporciona una distribución real. Por ejemplo, strategy.run(fn)
simplemente llamará a fn
. El código escrito con esta estrategia debe comportarse exactamente como el código escrito sin ninguna estrategia. Puede pensar en ello como una estrategia "no operativa".
La estrategia predeterminada es un singleton, y no se pueden crear más instancias de él. Se puede obtener usando tf.distribute.get_strategy()
fuera del alcance de cualquier estrategia explícita (la misma API que se puede usar para obtener la estrategia actual dentro del alcance de una estrategia explícita).
default_strategy = tf.distribute.get_strategy()
Esta estrategia tiene dos propósitos principales:
- Permite escribir código de biblioteca compatible con la distribución de forma incondicional. Por ejemplo, en
tf.optimizer
s puede usartf.distribute.get_strategy()
y usar esa estrategia para reducir gradientes; siempre devolverá un objeto de estrategia en el que podemos llamar a la API de reducción.
# 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
- Al igual que el código de biblioteca, se puede utilizar para escribir programas de usuarios finales para trabajar con y sin estrategia de distribución, sin requerir lógica condicional. Un fragmento de código de muestra que ilustra esto:
if tf.config.list_physical_devices('gpu'):
strategy = tf.distribute.MirroredStrategy()
else: # use default strategy
strategy = tf.distribute.get_strategy()
with strategy.scope():
# do something interesting
print(tf.Variable(1.))
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=1.0>
OneDeviceStrategy
tf.distribute.OneDeviceStrategy
es una estrategia para colocar todas las variables y el cálculo en un solo dispositivo especificado.
strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")
Esta estrategia es distinta de la estrategia predeterminada en varias formas. En la estrategia predeterminada, la lógica de ubicación de variables permanece sin cambios en comparación con la ejecución de TensorFlow sin ninguna estrategia de distribución. Pero cuando se usa OneDeviceStrategy
, todas las variables creadas en su alcance se colocan explícitamente en el dispositivo especificado. Además, cualquier función llamada a través de OneDeviceStrategy.run
también se colocará en el dispositivo especificado.
La entrada distribuida a través de esta estrategia se precargará en el dispositivo especificado. En la estrategia predeterminada, no hay distribución de entrada.
De manera similar a la estrategia predeterminada, esta estrategia también podría usarse para probar su código antes de cambiar a otras estrategias que realmente distribuyen a múltiples dispositivos / máquinas. Esto ejercitará la maquinaria de la estrategia de distribución un poco más que la estrategia predeterminada, pero no en la medida en que se utiliza MirroredStrategy
o TPUStrategy
etc. Si desea un código que se comporte como si no tuviera una estrategia, utilice la estrategia predeterminada.
Hasta ahora, ha visto las diferentes estrategias disponibles y cómo puede instanciarlas. Las siguientes secciones muestran las diferentes formas en las que puede utilizarlas para distribuir su formación.
Usando tf.distribute.Strategy
con tf.keras.Model.fit
tf.distribute.Strategy
está integrado en tf.keras
que es la implementación de TensorFlow de la especificación de la API de Keras . tf.keras
es una API de alto nivel para construir y entrenar modelos. Al integrarnos en el backend de tf.keras
, hemos facilitado la distribución de la formación escrita en el marco de formación de Keras mediante model.fit
.
Esto es lo que necesita cambiar en su código:
- Cree una instancia del
tf.distribute.Strategy
apropiado. - Mueva la creación del modelo, el optimizador y las métricas de Keras dentro del alcance de la
strategy.scope
.
Admitimos todo tipo de modelos de Keras: secuenciales, funcionales y subclasificados.
Aquí hay un fragmento de código para hacer esto para un modelo Keras muy simple con una capa densa:
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',).
Este ejemplo usa MirroredStrategy
para que pueda ejecutarlo en una máquina con varias GPU. strategy.scope()
indica a Keras qué estrategia utilizar para distribuir la formación. La creación de modelos / optimizadores / métricas dentro de este ámbito nos permite crear variables distribuidas en lugar de variables regulares. Una vez que esto esté configurado, puede ajustar su modelo como lo haría normalmente. MirroredStrategy
se encarga de replicar el entrenamiento del modelo en las GPU disponibles, agregar gradientes y más.
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',). 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.9810 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.4336 10/10 [==============================] - 1s 2ms/step - loss: 0.2299 0.22988776862621307
Aquí, untf.data.Dataset
proporciona la entrada de entrenamiento y evaluación. También puede usar matrices 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 [==============================] - 1s 2ms/step - loss: 0.1636 Epoch 2/2 10/10 [==============================] - 0s 2ms/step - loss: 0.0723 <tensorflow.python.keras.callbacks.History at 0x7f89057a2470>
En ambos casos (conjunto de datos o numpy), cada lote de la entrada dada se divide por igual entre las múltiples réplicas. Por ejemplo, si usa MirroredStrategy
con 2 GPU, cada lote de tamaño 10 se dividirá entre las 2 GPU, y cada una recibirá 5 ejemplos de entrada en cada paso. Cada época se entrenará más rápido a medida que agregue más GPU. Normalmente, querrá aumentar el tamaño de su lote a medida que agrega más aceleradores para hacer un uso efectivo de la potencia de cálculo adicional. También deberá volver a ajustar su tasa de aprendizaje, según el modelo. Puede usar strategy.num_replicas_in_sync
para obtener el número de réplicas.
# Compute global batch size using 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é es compatible ahora?
API de entrenamiento | EspejoEstrategia | TPUStrategy | MultiWorkerMirroredStrategy | ParameterServerStrategy | CentralStorageStrategy |
---|---|---|---|---|---|
API de Keras | Soportado | Soportado | Soporte experimental | Soporte experimental | Soporte experimental |
Ejemplos y tutoriales
Aquí hay una lista de tutoriales y ejemplos que ilustran la integración anterior de principio a fin con Keras:
- Tutorial para entrenar MNIST con
MirroredStrategy
. - Tutorial para entrenar MNIST usando
MultiWorkerMirroredStrategy
. - Guía para entrenar MNIST usando
TPUStrategy
. - Tutorial para el entrenamiento del servidor de parámetros en TensorFlow 2 con
ParameterServerStrategy
. - Repositorio de TensorFlow Model Garden que contiene colecciones de modelos de última generación implementados mediante varias estrategias.
Usando tf.distribute.Strategy
con ciclos de entrenamiento personalizados
Como ha visto, el uso de tf.distribute.Strategy
con Keras model.fit
requiere cambiar solo un par de líneas de su código. Con un poco más de esfuerzo, también puede usar tf.distribute.Strategy
con ciclos de entrenamiento personalizados.
Si necesita más flexibilidad y control sobre sus ciclos de entrenamiento de lo que es posible con Estimator o Keras, puede escribir ciclos de entrenamiento personalizados. Por ejemplo, al usar un GAN, es posible que desee realizar un número diferente de pasos de generador o discriminador en cada ronda. Del mismo modo, los marcos de alto nivel no son muy adecuados para la formación de aprendizaje por refuerzo.
Las clases tf.distribute.Strategy
proporcionan un conjunto básico de métodos para admitir ciclos de entrenamiento personalizados. El uso de estos puede requerir una reestructuración menor del código inicialmente, pero una vez hecho esto, debería poder cambiar entre GPU, TPU y varias máquinas simplemente cambiando la instancia de estrategia.
Aquí mostraremos un breve fragmento que ilustra este caso de uso para un ejemplo de entrenamiento simple usando el mismo modelo de Keras que antes.
Primero, cree el modelo y el optimizador dentro del alcance de la estrategia. Esto asegura que cualquier variable creada con el modelo y el optimizador sean variables reflejadas.
with mirrored_strategy.scope():
model = tf.keras.Sequential([tf.keras.layers.Dense(1, input_shape=(1,))])
optimizer = tf.keras.optimizers.SGD()
A continuación, cree el conjunto de datos de entrada y llame a tf.distribute.Strategy.experimental_distribute_dataset
para distribuir el conjunto de datos según la estrategia.
dataset = tf.data.Dataset.from_tensors(([1.], [1.])).repeat(100).batch(
global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)
Luego, defina un paso del entrenamiento. Utilicetf.GradientTape
para calcular gradientes y el optimizador para aplicar esos gradientes para actualizar las variables de nuestro modelo. Para distribuir este paso de entrenamiento, póngalo en una función train_step
y páselo a tf.distrbute.Strategy.run
junto con las entradas del conjunto de datos que obtuvo del dist_dataset
creado antes:
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)
Algunas otras cosas a tener en cuenta en el código anterior:
- Usó
tf.nn.compute_average_loss
para calcular la pérdida.tf.nn.compute_average_loss
suma la pérdida por ejemplo y divide la suma por el global_batch_size. Esto es importante porque más tarde, después de que se calculan los gradientes en cada réplica, se agregan a través de las réplicas sumándolas . - Usó la API
tf.distribute.Strategy.reduce
para agregar los resultados devueltos portf.distribute.Strategy.run
.tf.distribute.Strategy.run
devuelve resultados de cada réplica local en la estrategia y hay varias formas de consumir este resultado. Puedereduce
para obtener un valor agregado. También puede hacertf.distribute.Strategy.experimental_local_results
para obtener la lista de valores contenidos en el resultado, uno por réplica local. - Cuando se llama a
apply_gradients
dentro del alcance de una estrategia de distribución, se modifica su comportamiento. Específicamente, antes de aplicar gradientes en cada instancia paralela durante el entrenamiento sincrónico, realiza una suma total de réplicas de los gradientes.
Finalmente, una vez que haya definido el paso de entrenamiento, podemos iterar sobre dist_dataset
y ejecutar el entrenamiento en un ciclo:
for dist_inputs in dist_dataset:
print(distributed_train_step(dist_inputs))
tf.Tensor(0.88850546, shape=(), dtype=float32) tf.Tensor(0.8815902, shape=(), dtype=float32) tf.Tensor(0.87474185, shape=(), dtype=float32) tf.Tensor(0.8679599, shape=(), dtype=float32) tf.Tensor(0.86124384, shape=(), dtype=float32) tf.Tensor(0.8545932, shape=(), dtype=float32) tf.Tensor(0.8480073, shape=(), dtype=float32) tf.Tensor(0.8414857, shape=(), dtype=float32) tf.Tensor(0.8350279, shape=(), dtype=float32) tf.Tensor(0.8286335, shape=(), dtype=float32) tf.Tensor(0.8223018, shape=(), dtype=float32) tf.Tensor(0.81603223, shape=(), dtype=float32) tf.Tensor(0.8098244, shape=(), dtype=float32) tf.Tensor(0.8036777, shape=(), dtype=float32) tf.Tensor(0.7975916, shape=(), dtype=float32) tf.Tensor(0.79156566, shape=(), dtype=float32) tf.Tensor(0.78559923, shape=(), dtype=float32) tf.Tensor(0.77969193, shape=(), dtype=float32) tf.Tensor(0.773843, shape=(), dtype=float32) tf.Tensor(0.7680521, shape=(), dtype=float32)
En el ejemplo anterior, dist_dataset
sobre dist_dataset
para proporcionar información para tu entrenamiento. También proporcionamos tf.distribute.Strategy.make_experimental_numpy_dataset
para admitir numerosas entradas. Puede utilizar esta API para crear un conjunto de datos antes de llamar a tf.distribute.Strategy.experimental_distribute_dataset
.
Otra forma de iterar sobre sus datos es usar iteradores explícitamente. Es posible que desee hacer esto cuando desee ejecutar una determinada cantidad de pasos en lugar de iterar sobre todo el conjunto de datos. La iteración anterior ahora se modificaría para crear primero un iterador y luego llamar explícitamente a next
para obtener los datos de entrada.
iterator = iter(dist_dataset)
for _ in range(10):
print(distributed_train_step(next(iterator)))
tf.Tensor(0.7623187, shape=(), dtype=float32) tf.Tensor(0.7566423, shape=(), dtype=float32) tf.Tensor(0.7510221, shape=(), dtype=float32) tf.Tensor(0.7454578, shape=(), dtype=float32) tf.Tensor(0.739949, shape=(), dtype=float32) tf.Tensor(0.7344949, shape=(), dtype=float32) tf.Tensor(0.72909516, shape=(), dtype=float32) tf.Tensor(0.7237492, shape=(), dtype=float32) tf.Tensor(0.7184567, shape=(), dtype=float32) tf.Tensor(0.7132167, shape=(), dtype=float32)
Esto cubre el caso más simple de usar la API tf.distribute.Strategy
para distribuir ciclos de entrenamiento personalizados.
¿Qué es compatible ahora?
API de entrenamiento | EspejoEstrategia | TPUStrategy | MultiWorkerMirroredStrategy | ParameterServerStrategy | CentralStorageStrategy |
---|---|---|---|---|---|
Bucle de entrenamiento personalizado | Soportado | Soportado | Soporte experimental | Soporte experimental | Soporte experimental |
Ejemplos y tutoriales
A continuación, se muestran algunos ejemplos del uso de la estrategia de distribución con ciclos de entrenamiento personalizados:
- Tutorial para entrenar MNIST usando
MirroredStrategy
. - Guía para entrenar MNIST usando
TPUStrategy
. - Repositorio de TensorFlow Model Garden que contiene colecciones de modelos de última generación implementados mediante varias estrategias.
Otros temas
Esta sección cubre algunos temas que son relevantes para múltiples casos de uso.
Configuración de la variable de entorno TF_CONFIG
Para la capacitación de varios trabajadores, como se mencionó anteriormente, debe configurar la variable de entorno TF_CONFIG
para cada binario que se ejecuta en su clúster. La variable de entorno TF_CONFIG
es una cadena JSON que especifica qué tareas constituyen un clúster, sus direcciones y la función de cada tarea en el clúster. El repositorio de tensorflow / ecosistema proporciona una plantilla de Kubernetes en la que configura TF_CONFIG
para tus tareas de entrenamiento.
Hay dos componentes de TF_CONFIG: clúster y tarea. cluster proporciona información sobre el cluster de formación, que es un diccionario que consta de diferentes tipos de trabajos, como trabajador. En la capacitación de varios trabajadores, generalmente hay un trabajador que asume un poco más de responsabilidad, como guardar el punto de control y escribir un archivo de resumen para TensorBoard, además de lo que hace un trabajador habitual. A dicho trabajador se le llama trabajador 'jefe', y es habitual que el trabajador con índice 0 sea designado como trabajador principal (de hecho, así es como se implementa tf.distribute.Strategy). tarea, por otro lado, proporciona información de la tarea actual. El primer grupo de componentes es el mismo para todos los trabajadores, y la tarea del segundo componente es diferente en cada trabajador y especifica el tipo y el índice de ese trabajador.
Un ejemplo de TF_CONFIG
es:
os.environ["TF_CONFIG"] = json.dumps({
"cluster": {
"worker": ["host1:port", "host2:port", "host3:port"],
"ps": ["host4:port", "host5:port"]
},
"task": {"type": "worker", "index": 1}
})
Este TF_CONFIG
especifica que hay tres trabajadores y dos tareas ps en el clúster junto con sus hosts y puertos. La parte "tarea" especifica que el rol de la tarea actual en el clúster, trabajador 1 (el segundo trabajador). Los roles válidos en un clúster son "jefe", "trabajador", "ps" y "evaluador". No debería haber ningún trabajo "ps" excepto cuando se usa tf.distribute.experimental.ParameterServerStrategy
.
¿Que sigue?
tf.distribute.Strategy
está activamente en desarrollo. Pruébelo y proporcione sus comentarios con los problemas de GitHub .