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:
-
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 claveglobal_batch_size=
. Sin lotes cortos, el valor predeterminado es equivalente atf.nn.compute_average_loss(..., global_batch_size=global_batch_size)
con elglobal_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). -
Usaste
tf.nn.scale_regularization_loss
para escalar pérdidas de regularización registradas con elMannequin
objeto, si lo hay, por1/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. -
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. -
También usaste el
tf.distribute.Technique.scale back
API para agregar los resultados devueltos portf.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. Puedescale back
ellos para obtener un valor agregado. También puedes hacertf.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 |
|
|
|
|
|
---|---|---|---|---|---|
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:
- Tutorial: capacitación con un bucle de entrenamiento personalizado y
MirroredStrategy
. - Tutorial: capacitación con un bucle de entrenamiento personalizado y
MultiWorkerMirroredStrategy
. - Guía: contiene un ejemplo de un bucle de entrenamiento personalizado con
TPUStrategy
. - Tutorial: entrenamiento del servidor de parámetros con un bucle de entrenamiento personalizado y
ParameterServerStrategy
. - 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 comotf.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