Home Ciencia y Tecnología Bucles de entrenamiento de flujo tensor personalizado facilitados

Bucles de entrenamiento de flujo tensor personalizado facilitados

36
0

Descripción basic del contenido

  • Use tf.distribute.technique con bucles de capacitación personalizados
  • ¿Qué es suitable ahora?
  • Ejemplos y tutoriales
  • Otros temas
  • Configuración de la variable de entorno TF_CONFIG
  • ¿Qué sigue?

Use tf.distribute.technique con bucles de capacitación personalizados

Como se demostró anteriormente, usando tf.distribute.Technique con keras Mannequin.match requiere cambiar solo un par de líneas de su código. Con un poco más de esfuerzo, también puedes usar tf.distribute.Technique con bucles de entrenamiento personalizados.

Si necesita más flexibilidad y management sobre sus bucles de entrenamiento de lo posible con estimador o keras, puede escribir bucles de entrenamiento personalizados. Por ejemplo, cuando usa un GaN, es posible que desee tomar 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 capacitación de aprendizaje de refuerzo.

El tf.distribute.Technique Las clases proporcionan un conjunto central de métodos para admitir bucles de capacitación personalizados. El uso de estos puede requerir una reestructuración menor del código inicialmente, pero una vez que se haga, debe poder cambiar entre GPU, TPU y múltiples máquinas simplemente cambiando la instancia de la estrategia.

A continuación se muestra un breve fragmento que ilustra este caso de uso para un ejemplo de entrenamiento easy que usa el mismo modelo 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():
  mannequin = tf.keras.Sequential([
      tf.keras.layers.Dense(1, input_shape=(1,),
                            kernel_regularizer=tf.keras.regularizers.L2(1e-4))])
  optimizer = tf.keras.optimizers.SGD()

A continuación, cree el conjunto de datos de entrada y la llamada tf.distribute.Technique.experimental_distribute_dataset Para distribuir el conjunto de datos en función de la estrategia.

dataset = tf.information.Dataset.from_tensors(([1.], [1.])).repeat(1000).batch(
    global_batch_size)
dist_dataset = mirrored_strategy.experimental_distribute_dataset(dataset)

Luego, defina un paso del entrenamiento. Usar tf.GradientTape Para calcular los gradientes y el optimizador para aplicar esos gradientes para actualizar las variables de su modelo. Para distribuir este paso de entrenamiento, ponlo en una función train_step y pasarlo a tf.distribute.Technique.run junto con las entradas del conjunto de datos que obtuvo del dist_dataset creado antes:

# Units `discount=NONE` to go away it to tf.nn.compute_average_loss() under.
loss_object = tf.keras.losses.BinaryCrossentropy(
  from_logits=True,
  discount=tf.keras.losses.Discount.NONE)

def train_step(inputs):
  options, labels = inputs

  with tf.GradientTape() as tape:
    predictions = mannequin(options, coaching=True)
    per_example_loss = loss_object(labels, predictions)
    loss = tf.nn.compute_average_loss(per_example_loss)
    model_losses = mannequin.losses
    if model_losses:
      loss += tf.nn.scale_regularization_loss(tf.add_n(model_losses))

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

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

Algunas otras cosas a tener en cuenta en el código anterior:

  1. Usaste tf.nn.compute_average_loss Para reducir las pérdidas de predicción por ejemplo a un escalar. tf.nn.compute_average_loss Sume la pérdida por ejemplo y divide la suma del tamaño world de lotes. Esto es importante porque más tarde después de los gradientes se calculan en cada réplica, se agregan a través de las réplicas por sumador a ellos.

    Por defecto, se considera el tamaño world de lotes tf.get_strategy().num_replicas_in_sync * tf.form(per_example_loss)[0]. También se puede especificar explícitamente como un argumento de palabras clave global_batch_size=. Sin lotes cortos, el valor predeterminado es equivalente a tf.nn.compute_average_loss(..., global_batch_size=global_batch_size) con el global_batch_size definido arriba. (Para obtener más información sobre lotes cortos y cómo evitarlos o manejarlos, consulte el tutorial de entrenamiento personalizado).

  2. Usaste tf.nn.scale_regularization_loss para escalar pérdidas de regularización registradas con el Mannequin objeto, si lo hay, por 1/num_replicas_in_sync también. Para esas pérdidas de regularización que dependen de la entrada, se cae en el código de modelado, no en el bucle de entrenamiento personalizado, para realizar el promedio sobre el tamaño de lotes por duplicate (!); De esa manera, el código de modelado puede permanecer agnóstico de la replicación, mientras que el bucle de entrenamiento permanece agnóstico de cómo se calculan las pérdidas de regularización.

  3. Cuando llamas apply_gradients Dentro de un alcance de la estrategia de distribución, su comportamiento se modifica. Específicamente, antes de aplicar gradientes en cada instancia paralela durante el entrenamiento sincrónico, realiza una suma de las reemplazo de los gradientes.

  4. También usaste el tf.distribute.Technique.scale back API para agregar los resultados devueltos por tf.distribute.Technique.run para informar. tf.distribute.Technique.run Devuelve los resultados de cada réplica native en la estrategia, y hay múltiples formas de consumir este resultado. Puede scale back ellos para obtener un valor agregado. También puedes hacer tf.distribute.Technique.experimental_local_results Para obtener la lista de valores contenidos en el resultado, uno por réplica native.

Finalmente, una vez que haya definido el paso de entrenamiento, puede iterar sobre dist_dataset y ejecute el entrenamiento en un bucle:

for dist_inputs in dist_dataset:
  print(distributed_train_step(dist_inputs))
tf.Tensor(0.9024367, form=(), dtype=float32)
tf.Tensor(0.8953863, form=(), dtype=float32)
tf.Tensor(0.8884038, form=(), dtype=float32)
tf.Tensor(0.88148874, form=(), dtype=float32)
tf.Tensor(0.87464076, form=(), dtype=float32)
tf.Tensor(0.86785895, form=(), dtype=float32)
tf.Tensor(0.86114323, form=(), dtype=float32)
tf.Tensor(0.8544927, form=(), dtype=float32)
tf.Tensor(0.84790725, form=(), dtype=float32)
tf.Tensor(0.841386, form=(), dtype=float32)
tf.Tensor(0.83492863, form=(), dtype=float32)
tf.Tensor(0.8285344, form=(), dtype=float32)
tf.Tensor(0.82220304, form=(), dtype=float32)
tf.Tensor(0.8159339, form=(), dtype=float32)
tf.Tensor(0.8097264, form=(), dtype=float32)
tf.Tensor(0.8035801, form=(), dtype=float32)
tf.Tensor(0.79749453, form=(), dtype=float32)
tf.Tensor(0.79146886, form=(), dtype=float32)
tf.Tensor(0.785503, form=(), dtype=float32)
tf.Tensor(0.779596, form=(), dtype=float32)
tf.Tensor(0.77374756, form=(), dtype=float32)
tf.Tensor(0.7679571, form=(), dtype=float32)
tf.Tensor(0.7622242, form=(), dtype=float32)
tf.Tensor(0.7565481, form=(), dtype=float32)
tf.Tensor(0.75092846, form=(), dtype=float32)
tf.Tensor(0.7453647, form=(), dtype=float32)
tf.Tensor(0.73985624, form=(), dtype=float32)
tf.Tensor(0.7344028, form=(), dtype=float32)
tf.Tensor(0.7290035, form=(), dtype=float32)
tf.Tensor(0.723658, form=(), dtype=float32)
tf.Tensor(0.7183659, form=(), dtype=float32)
tf.Tensor(0.71312654, form=(), dtype=float32)
tf.Tensor(0.7079393, form=(), dtype=float32)
tf.Tensor(0.70280397, form=(), dtype=float32)
tf.Tensor(0.6977197, form=(), dtype=float32)
tf.Tensor(0.69268626, form=(), dtype=float32)
tf.Tensor(0.687703, form=(), dtype=float32)
tf.Tensor(0.68276954, form=(), dtype=float32)
tf.Tensor(0.67788523, form=(), dtype=float32)
tf.Tensor(0.6730496, form=(), dtype=float32)
tf.Tensor(0.66826224, form=(), dtype=float32)
tf.Tensor(0.66352266, form=(), dtype=float32)
tf.Tensor(0.6588302, form=(), dtype=float32)
tf.Tensor(0.6541846, form=(), dtype=float32)
tf.Tensor(0.6495853, form=(), dtype=float32)
tf.Tensor(0.64503175, form=(), dtype=float32)
tf.Tensor(0.6405235, form=(), dtype=float32)
tf.Tensor(0.6360602, form=(), dtype=float32)
tf.Tensor(0.6316412, form=(), dtype=float32)
tf.Tensor(0.62726617, form=(), dtype=float32)
tf.Tensor(0.6229345, form=(), dtype=float32)
tf.Tensor(0.61864597, form=(), dtype=float32)
tf.Tensor(0.6143999, form=(), dtype=float32)
tf.Tensor(0.6101959, form=(), dtype=float32)
tf.Tensor(0.60603356, form=(), dtype=float32)
tf.Tensor(0.60191244, form=(), dtype=float32)
tf.Tensor(0.597832, form=(), dtype=float32)
tf.Tensor(0.5937919, form=(), dtype=float32)
tf.Tensor(0.5897917, form=(), dtype=float32)
tf.Tensor(0.585831, form=(), dtype=float32)
tf.Tensor(0.58190924, form=(), dtype=float32)
tf.Tensor(0.5780261, form=(), dtype=float32)
tf.Tensor(0.57418114, form=(), dtype=float32)
tf.Tensor(0.57037395, form=(), dtype=float32)
tf.Tensor(0.5666041, form=(), dtype=float32)
tf.Tensor(0.56287116, form=(), dtype=float32)
tf.Tensor(0.55917484, form=(), dtype=float32)
tf.Tensor(0.5555145, form=(), dtype=float32)
tf.Tensor(0.55189, form=(), dtype=float32)
tf.Tensor(0.54830086, form=(), dtype=float32)
tf.Tensor(0.54474664, form=(), dtype=float32)
tf.Tensor(0.54122704, form=(), dtype=float32)
tf.Tensor(0.5377416, form=(), dtype=float32)
tf.Tensor(0.5342899, form=(), dtype=float32)
tf.Tensor(0.5308717, form=(), dtype=float32)
tf.Tensor(0.5274865, form=(), dtype=float32)
tf.Tensor(0.52413404, form=(), dtype=float32)
tf.Tensor(0.52081394, form=(), dtype=float32)
tf.Tensor(0.51752573, form=(), dtype=float32)
tf.Tensor(0.5142692, form=(), dtype=float32)
tf.Tensor(0.51104385, form=(), dtype=float32)
tf.Tensor(0.50784945, form=(), dtype=float32)
tf.Tensor(0.50468564, form=(), dtype=float32)
tf.Tensor(0.50155205, form=(), dtype=float32)
tf.Tensor(0.49844825, form=(), dtype=float32)
tf.Tensor(0.4953741, form=(), dtype=float32)
tf.Tensor(0.49232918, form=(), dtype=float32)
tf.Tensor(0.4893132, form=(), dtype=float32)
tf.Tensor(0.48632562, form=(), dtype=float32)
tf.Tensor(0.4833664, form=(), dtype=float32)
tf.Tensor(0.4804351, form=(), dtype=float32)
tf.Tensor(0.47753143, form=(), dtype=float32)
tf.Tensor(0.47465506, form=(), dtype=float32)
tf.Tensor(0.47180572, form=(), dtype=float32)
tf.Tensor(0.46898302, form=(), dtype=float32)
tf.Tensor(0.4661867, form=(), dtype=float32)
tf.Tensor(0.46341658, form=(), dtype=float32)
tf.Tensor(0.4606722, form=(), dtype=float32)
tf.Tensor(0.4579534, form=(), dtype=float32)
tf.Tensor(0.4552598, form=(), dtype=float32)
tf.Tensor(0.45259115, form=(), dtype=float32)
tf.Tensor(0.44994718, form=(), dtype=float32)
tf.Tensor(0.44732755, form=(), dtype=float32)
tf.Tensor(0.44473216, form=(), dtype=float32)
tf.Tensor(0.44216052, form=(), dtype=float32)
tf.Tensor(0.4396125, form=(), dtype=float32)
tf.Tensor(0.43708783, form=(), dtype=float32)
tf.Tensor(0.4345862, form=(), dtype=float32)
tf.Tensor(0.4321074, form=(), dtype=float32)
tf.Tensor(0.42965108, form=(), dtype=float32)
tf.Tensor(0.4272171, form=(), dtype=float32)
tf.Tensor(0.42480516, form=(), dtype=float32)
tf.Tensor(0.42241505, form=(), dtype=float32)
tf.Tensor(0.42004645, form=(), dtype=float32)
tf.Tensor(0.41769922, form=(), dtype=float32)
tf.Tensor(0.41537297, form=(), dtype=float32)
tf.Tensor(0.41306767, form=(), dtype=float32)
tf.Tensor(0.41078293, form=(), dtype=float32)
tf.Tensor(0.4085186, form=(), dtype=float32)
tf.Tensor(0.4062744, form=(), dtype=float32)
tf.Tensor(0.4040502, form=(), dtype=float32)
tf.Tensor(0.40184572, form=(), dtype=float32)
tf.Tensor(0.39966068, form=(), dtype=float32)
tf.Tensor(0.3974949, form=(), dtype=float32)
tf.Tensor(0.39534825, form=(), dtype=float32)
tf.Tensor(0.39322042, form=(), dtype=float32)
tf.Tensor(0.39111122, form=(), dtype=float32)
tf.Tensor(0.3890205, form=(), dtype=float32)
tf.Tensor(0.38694802, form=(), dtype=float32)
tf.Tensor(0.38489357, form=(), dtype=float32)
tf.Tensor(0.38285697, form=(), dtype=float32)
tf.Tensor(0.38083804, form=(), dtype=float32)
tf.Tensor(0.3788365, form=(), dtype=float32)
tf.Tensor(0.37685227, form=(), dtype=float32)
tf.Tensor(0.3748851, form=(), dtype=float32)
tf.Tensor(0.37293482, form=(), dtype=float32)
tf.Tensor(0.37100127, form=(), dtype=float32)
tf.Tensor(0.36908418, form=(), dtype=float32)
tf.Tensor(0.36718345, form=(), dtype=float32)
tf.Tensor(0.3652989, form=(), dtype=float32)
tf.Tensor(0.36343032, form=(), dtype=float32)
tf.Tensor(0.36157757, form=(), dtype=float32)
tf.Tensor(0.35974047, form=(), dtype=float32)
tf.Tensor(0.3579188, form=(), dtype=float32)
tf.Tensor(0.35611248, form=(), dtype=float32)
tf.Tensor(0.3543213, form=(), dtype=float32)
tf.Tensor(0.35254508, form=(), dtype=float32)
tf.Tensor(0.3507837, form=(), dtype=float32)
tf.Tensor(0.34903696, form=(), dtype=float32)
tf.Tensor(0.34730473, form=(), dtype=float32)
tf.Tensor(0.3455869, form=(), dtype=float32)
tf.Tensor(0.3438832, form=(), dtype=float32)
tf.Tensor(0.34219357, form=(), dtype=float32)
tf.Tensor(0.3405178, form=(), dtype=float32)
tf.Tensor(0.3388558, form=(), dtype=float32)
tf.Tensor(0.3372074, form=(), dtype=float32)
tf.Tensor(0.33557245, form=(), dtype=float32)
tf.Tensor(0.33395082, form=(), dtype=float32)
tf.Tensor(0.33234236, form=(), dtype=float32)
tf.Tensor(0.33074695, form=(), dtype=float32)
tf.Tensor(0.32916442, form=(), dtype=float32)
tf.Tensor(0.3275946, form=(), dtype=float32)
tf.Tensor(0.3260375, form=(), dtype=float32)
tf.Tensor(0.3244928, form=(), dtype=float32)
tf.Tensor(0.3229605, form=(), dtype=float32)
tf.Tensor(0.32144046, form=(), dtype=float32)
tf.Tensor(0.31993246, form=(), dtype=float32)
tf.Tensor(0.3184365, form=(), dtype=float32)
tf.Tensor(0.31695238, form=(), dtype=float32)
tf.Tensor(0.31548, form=(), dtype=float32)
tf.Tensor(0.31401917, form=(), dtype=float32)
tf.Tensor(0.3125699, form=(), dtype=float32)
tf.Tensor(0.31113195, form=(), dtype=float32)
tf.Tensor(0.30970532, form=(), dtype=float32)
tf.Tensor(0.3082898, form=(), dtype=float32)
tf.Tensor(0.30688527, form=(), dtype=float32)
tf.Tensor(0.3054917, form=(), dtype=float32)
tf.Tensor(0.30410892, form=(), dtype=float32)
tf.Tensor(0.3027368, form=(), dtype=float32)
tf.Tensor(0.30137527, form=(), dtype=float32)
tf.Tensor(0.3000242, form=(), dtype=float32)
tf.Tensor(0.29868355, form=(), dtype=float32)
tf.Tensor(0.29735315, form=(), dtype=float32)
tf.Tensor(0.29603288, form=(), dtype=float32)
tf.Tensor(0.29472268, form=(), dtype=float32)
tf.Tensor(0.2934224, form=(), dtype=float32)
tf.Tensor(0.29213202, form=(), dtype=float32)
tf.Tensor(0.29085135, form=(), dtype=float32)
tf.Tensor(0.28958035, form=(), dtype=float32)
tf.Tensor(0.2883189, form=(), dtype=float32)
tf.Tensor(0.28706694, form=(), dtype=float32)
tf.Tensor(0.28582436, form=(), dtype=float32)
tf.Tensor(0.28459102, form=(), dtype=float32)
tf.Tensor(0.28336692, form=(), dtype=float32)
tf.Tensor(0.2821518, form=(), dtype=float32)
tf.Tensor(0.28094578, form=(), dtype=float32)
tf.Tensor(0.27974862, form=(), dtype=float32)
tf.Tensor(0.2785603, form=(), dtype=float32)
tf.Tensor(0.27738073, form=(), dtype=float32)
tf.Tensor(0.2762098, form=(), dtype=float32)

En el ejemplo anterior, iteró sobre el dist_dataset Para proporcionar información a su capacitación. También se le proporciona el tf.distribute.Technique.make_experimental_numpy_dataset para admitir entradas numpy. Puede usar esta API para crear un conjunto de datos antes de llamar tf.distribute.Technique.experimental_distribute_dataset.

Otra forma de iterar sobre sus datos es usar explícitamente iteradores. Es posible que desee hacer esto cuando desee ejecutar para un número dado de pasos en lugar de iterar en todo el conjunto de datos. La iteración anterior ahora se modificaría para crear primero un iterador y luego llamar explícitamente subsequent en él para obtener los datos de entrada.

iterator = iter(dist_dataset)
for _ in vary(10):
  print(distributed_train_step(subsequent(iterator)))
tf.Tensor(0.27504745, form=(), dtype=float32)
tf.Tensor(0.2738936, form=(), dtype=float32)
tf.Tensor(0.2727481, form=(), dtype=float32)
tf.Tensor(0.27161098, form=(), dtype=float32)
tf.Tensor(0.27048206, form=(), dtype=float32)
tf.Tensor(0.26936132, form=(), dtype=float32)
tf.Tensor(0.26824862, form=(), dtype=float32)
tf.Tensor(0.26714393, form=(), dtype=float32)
tf.Tensor(0.26604718, form=(), dtype=float32)
tf.Tensor(0.26495826, form=(), dtype=float32)

Esto cubre el caso más easy de usar tf.distribute.Technique API para distribuir bucles de capacitación personalizados.

¿Qué es suitable ahora?

API de entrenamiento

MirroredStrategy

TPUStrategy

MultiWorkerMirroredStrategy

ParameterServerStrategy

CentralStorageStrategy

Bucle de entrenamiento personalizado

Appropriate

Appropriate

Appropriate

Soporte experimental

Soporte experimental

Ejemplos y tutoriales

Aquí hay algunos ejemplos para usar estrategias de distribución con bucles de capacitación personalizados:

  1. Tutorial: capacitación con un bucle de entrenamiento personalizado y MirroredStrategy.
  2. Tutorial: capacitación con un bucle de entrenamiento personalizado y MultiWorkerMirroredStrategy.
  3. Guía: contiene un ejemplo de un bucle de entrenamiento personalizado con TPUStrategy.
  4. Tutorial: entrenamiento del servidor de parámetros con un bucle de entrenamiento personalizado y ParameterServerStrategy.
  5. TensorFlow Mannequin Repositorio de jardín que contiene colecciones de modelos de vanguardia implementados utilizando diversas 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 múltiples trabajadores, como se mencionó anteriormente, debe configurar el 'TF_CONFIG' Variable de entorno para cada binario que se ejecuta en su clúster. El 'TF_CONFIG' El entorno variable es una cadena JSON que especifica qué tareas constituyen un clúster, sus direcciones y el papel de cada tarea en el clúster. El tensorflow/ecosystem Repo proporciona una plantilla de Kubernetes, que se establece 'TF_CONFIG' para sus tareas de entrenamiento.

Hay dos componentes de 'TF_CONFIG': un clúster y una tarea.

  • Un clúster proporciona información sobre el clúster de capacitación, que es un DICT que consiste en diferentes tipos de trabajos, como los trabajadores. En la capacitación de múltiples trabajadores, generalmente hay un trabajador que asume un poco más de responsabilidad, como guardar el punto de management y escribir un archivo de resumen para TensorBoard, además de lo que hace un trabajador common. Dicho trabajador se conoce como el trabajador “jefe”, y es ordinary que el trabajador con índice 0 se designa como el principal trabajador (de hecho, así es como tf.distribute.Technique se implementa).
  • Una tarea, por otro lado, proporciona información sobre la tarea precise. El primer clúster de componentes es el mismo para todos los trabajadores, y la segunda tarea de 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": {
        "employee": ["host1:port", "host2:port", "host3:port"],
        "ps": ["host4:port", "host5:port"]
    },
   "process": {"kind": "employee", "index": 1}
})

Este 'TF_CONFIG' Especifica que hay tres trabajadores y dos "ps" tareas en el "cluster" junto con sus anfitriones y puertos. El "process" parte especifica el papel de la tarea precise en el "cluster"-obrero 1 (el segundo trabajador). Los roles válidos en un clúster son "chief", "employee", "ps"y "evaluator". No debería haber "ps" trabajo excepto cuando se usa tf.distribute.experimental.ParameterServerStrategy.

¿Qué sigue?

tf.distribute.Technique está activamente en desarrollo. Pruébelo y proporcione sus comentarios utilizando problemas de GitHub.

Publicado originalmente en el Flujo tensor Sitio net, este artículo aparece aquí en un nuevo titular y tiene licencia bajo CC por 4.0. Muestras de código compartidas bajo la licencia Apache 2.0.

fuente

LEAVE A REPLY

Please enter your comment!
Please enter your name here