Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
tensorflow
GitHub Repository: tensorflow/docs-l10n
Path: blob/master/site/es-419/guide/effective_tf2.ipynb
25115 views
Kernel: Python 3
#@title Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License.

Tensorflow 2 efectivo

Descripción general

En esta guía se brinda una lista de las mejores prácticas para escribir código con TensorFlow 2 (TF2). Está escrita para usuarios que han cambiado recientemente desde TensorFlow 1 (TF1) a TF2. Para más información sobre cómo migrar código TF1 a TF2, consulte la sección de la guía en que se trata el tema de la migración.

Preparación

Importe TensorFlow y otras dependencias para usar los ejemplos de esta guía.

import tensorflow as tf import tensorflow_datasets as tfds

Recomendaciones para TensorFlow 2 idiomático

Refactorización del código en módulos más pequeños

Una buena práctica es la de refactorizar el código en funciones más pequeñas a las que llamamos cuando es necesario. Para un mejor desempeño, debería tratar de decorar los bloques de cálculo más grandes posibles en una tf.function (tenga en cuenta que las funciones Python anidadas llamadas por una tf.function no necesitan sus propias decoraciones separadas, a menos que desee usar jit_compile diferentes para la tf.function). Dependiendo de su caso de uso, podría tratarse de múltiples pasos de entrenamiento o incluso de un ciclo de entrenamiento completo. Para casos de interferencia, podría ser un solo pase hacia adelante del modelo.

Ajuste de la tasa de aprendizaje predeterminada para algunos tf.keras.optimizer

Algunos optimizadores Keras tienen tasas de aprendizaje diferentes en TF2. Si nota un cambio en el comportamiento de convergencia en sus modelos, controle las tasas de aprendizaje predeterminadas.

No hay cambios para optimizers.SGD, optimizers.Adam ni optimizers.RMSprop.

Las siguientes tasas de aprendizaje han cambiado:

  • optimizers.Adagrad de 0.01 a 0.001

  • optimizers.Adadelta de 1.0 a 0.001

  • optimizers.Adamax de 0.002 a 0.001

  • optimizers.Nadam de 0.002 a 0.001

Use tf.Module y capas Keras para gestionar las variables

Los tf.Moduley las tf.keras.layers.Layer ofrecen propiedades convenientes en variables y trainable_variables que pueden reunir recursivamente todas las variables dependientes. Todo esto facilita la gestión de variables a nivel local a donde se están usando.

Las capas o modelos Keras heredan de tf.train.Checkpointable y se integran con @tf.function, lo que hace posible directamente aplicar puntos de control (checkpoint) o exportar SavedModels de objetos Keras. No necesariamente hay que usar la API Model.fit de Keras para aprovechar estas integraciones.

Lea la sección sobre transferencia de aprendizaje y ajuste fino en la guía de Keras para entender cómo recopilar un subconjunto de variables relevantes con Keras.

Combinación de los tf.data.Dataset y la tf.function

El paquete (tfds) de conjuntos de datos de TensorFlow contiene utilidades para cargar conjuntos de datos predeterminados como los objetos tf.data.Dataset. Para este ejemplo, puede cargar el conjunto de datos MNIST con tfds:

datasets, info = tfds.load(name='mnist', with_info=True, as_supervised=True) mnist_train, mnist_test = datasets['train'], datasets['test']

Después, prepare el conjunto de datos para entrenamiento:

  • Redimensione cada imagen.

  • Aleatorice el orden de los ejemplos.

  • Recolecte lotes de imágenes y etiquetas.

BUFFER_SIZE = 10 # Use a much larger value for real code BATCH_SIZE = 64 NUM_EPOCHS = 5 def scale(image, label): image = tf.cast(image, tf.float32) image /= 255 return image, label

Para no hacer muy extenso el ejemplo, ajuste el conjunto de datos para que solamente devuelva 5 lotes:

train_data = mnist_train.map(scale).shuffle(BUFFER_SIZE).batch(BATCH_SIZE) test_data = mnist_test.map(scale).batch(BATCH_SIZE) STEPS_PER_EPOCH = 5 train_data = train_data.take(STEPS_PER_EPOCH) test_data = test_data.take(STEPS_PER_EPOCH)
image_batch, label_batch = next(iter(train_data))

Use iteraciones Python regulares para iterar sobre datos de entrenamiento que entren en la memoria. De lo contrario, tf.data.Dataset será la mejor opción para transmitir los datos de entrenamiento desde el disco. Los conjuntos de datos son iterables (no iteradores) y funcionan igual que los iterables de Python en ejecución eager. Puede utilizar por completo las funciones de preextracción o streaming asincrónicas de conjuntos de datos encapsulando el código en tf.function, que reemplaza la iteración Python con las operaciones de grafos equivalentes mediante AutoGraph.

@tf.function def train(model, dataset, optimizer): for x, y in dataset: with tf.GradientTape() as tape: # training=True is only needed if there are layers with different # behavior during training versus inference (e.g. Dropout). prediction = model(x, training=True) loss = loss_fn(prediction, y) gradients = tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables))

Si usa la API Model.fit de Keras, no tendrá que preocuparse por la iteración del conjunto de datos.

model.compile(optimizer=optimizer, loss=loss_fn) model.fit(dataset)

Uso de ciclos de entrenamiento Keras

Cuando no es necesario realizar un control de bajo nivel del proceso de entrenamiento, se recomienda usar los métodos integrados fit, evaluate y predict de Keras. Estos métodos ofrecen una interfaz uniforme para entrenar el modelo, que es independiente del tipo de implementación (secuencial, funcional o de subclase).

Las ventajas que ofrecen estos métodos incluyen lo siguiente:

  • Aceptan arreglos Numpy, generadores de Python y tf.data.Datasets.

  • Aplican automáticamente regularización y pérdidas por activación.

  • Son compatibles con tf.distribute, donde el código de entrenamiento sigue siendo el mismo independientemente de la configuración que tenga el hardware.

  • Son compatibles con invocables arbitrarios como las pérdidas o las métricas.

  • Son compatibles con invocables como tf.keras.callbacks.TensorBoard y otros invocables personalizados.

  • Son ejecutantes, que usan automáticamente grafos de TensorFlow.

A continuación, un ejemplo del entrenamiento de un modelo con Dataset. Para más detalles sobre cómo funciona, consulte los tutoriales.

model = tf.keras.Sequential([ tf.keras.layers.Conv2D(32, 3, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.02), input_shape=(28, 28, 1)), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Flatten(), tf.keras.layers.Dropout(0.1), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.BatchNormalization(), tf.keras.layers.Dense(10) ]) # Model is the full model w/o custom layers model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy']) model.fit(train_data, epochs=NUM_EPOCHS) loss, acc = model.evaluate(test_data) print("Loss {}, Accuracy {}".format(loss, acc))

Personalización de entrenamiento y escritura del ciclo propio

Si los modelos Keras le resultan útiles, pero necesita más flexibilidad y control del paso o los ciclos de entrenamiento externos, puede implementar sus propios pasos o incluso los ciclos enteros. Para más información sobre personalización de fit consulte la guía de Keras.

También puede implementar muchas cosas como un tf.keras.callbacks.Callback.

Este método tiene muchas de las ventajas que mencionamos previamente, pero además le permite controlar el paso de entrenamiento e incluso el ciclo externo.

En un ciclo de entrenamiento estándar hay tres pasos:

  1. Iterar sobre un generaror Python o un tf.data.Dataset para obtener lotes de muestras.

  2. Usar tf.GradientTape para recopilar los gradientes.

  3. Usar uno de los tf.keras.optimizers para aplicar las actualizaciones de pesos a las variables del modelo.

Recuerde:

  • Incluya siempre un argumento de training en el método call de los modelos y las capas en subclases.

  • Asegúrese de invocar al modelo con el argumento de training establecido correctamente.

  • Dependiendo del uso, las variables del modelo pueden no existir hasta que el modelo esté funcionando en un lote de datos.

  • Debe manejar manualmente algunas cosas como las pérdidas de regularización del modelo.

No hay necesidad de ejecutar inicializadores variables ni de agregar dependencias de control manual. La tf.function se ocupa de las dependencias de control automático y de la inicialización variable en la creación.

model = tf.keras.Sequential([ tf.keras.layers.Conv2D(32, 3, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.02), input_shape=(28, 28, 1)), tf.keras.layers.MaxPooling2D(), tf.keras.layers.Flatten(), tf.keras.layers.Dropout(0.1), tf.keras.layers.Dense(64, activation='relu'), tf.keras.layers.BatchNormalization(), tf.keras.layers.Dense(10) ]) optimizer = tf.keras.optimizers.Adam(0.001) loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) @tf.function def train_step(inputs, labels): with tf.GradientTape() as tape: predictions = model(inputs, training=True) regularization_loss=tf.math.add_n(model.losses) pred_loss=loss_fn(labels, predictions) total_loss=pred_loss + regularization_loss gradients = tape.gradient(total_loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) for epoch in range(NUM_EPOCHS): for inputs, labels in train_data: train_step(inputs, labels) print("Finished epoch", epoch)

Aproveche tf.function con el flujo de control de Python

tf.function ofrece una forma de convertir el flujo de control dependiente de datos en equivalentes de modo grafo como tf.cond y tf.while_loop.

Un lugar común donde aparece el flujo de control dependiente de datos es en los modelos secuenciales.tf.keras.layers.RNN encapsula una celda RNN, con lo que permite desplegar la recurrencia, ya sea de forma dinámica o estática.

class DynamicRNN(tf.keras.Model): def __init__(self, rnn_cell): super(DynamicRNN, self).__init__(self) self.cell = rnn_cell @tf.function(input_signature=[tf.TensorSpec(dtype=tf.float32, shape=[None, None, 3])]) def call(self, input_data): # [batch, time, features] -> [time, batch, features] input_data = tf.transpose(input_data, [1, 0, 2]) timesteps = tf.shape(input_data)[0] batch_size = tf.shape(input_data)[1] outputs = tf.TensorArray(tf.float32, timesteps) state = self.cell.get_initial_state(batch_size = batch_size, dtype=tf.float32) for i in tf.range(timesteps): output, state = self.cell(input_data[i], state) outputs = outputs.write(i, output) return tf.transpose(outputs.stack(), [1, 0, 2]), state
lstm_cell = tf.keras.layers.LSTMCell(units = 13) my_rnn = DynamicRNN(lstm_cell) outputs, state = my_rnn(tf.random.normal(shape=[10,20,3])) print(outputs.shape)

Para más información, lea la guía tf.function.

Métricas y pérdidas de estilo nuevo

Tanto las métricas como las pérdidas son objetos que funcionan con ejecución eager y en tf.function.

Los objetos de pérdida son invocables y esperan (y_true y y_pred) como argumentos:

cce = tf.keras.losses.CategoricalCrossentropy(from_logits=True) cce([[1, 0]], [[-1.0,3.0]]).numpy()

Uso de métricas para recopilar y mostrar datos

Puede usar tf.metrics para agregar datos y tf.summary para registrar resúmenes y realizar la redirección a un escritor con un gestor de contexto. Los resúmenes se emiten directamente al escritor, lo que significa que debe proporcionarle el valor step en el sitio invocado (callsite).

summary_writer = tf.summary.create_file_writer('/tmp/summaries') with summary_writer.as_default(): tf.summary.scalar('loss', 0.1, step=42)

Use tf.metrics para agregar datos antes de registrarlos como resúmenes. Las métricas consideran los datos con estado (stateful); acumulan valores y devuelven un resultado acumulado cuando se llama al método result (como Mean.result). Borre los valores acumulados con Model.reset_states.

def train(model, optimizer, dataset, log_freq=10): avg_loss = tf.keras.metrics.Mean(name='loss', dtype=tf.float32) for images, labels in dataset: loss = train_step(model, optimizer, images, labels) avg_loss.update_state(loss) if tf.equal(optimizer.iterations % log_freq, 0): tf.summary.scalar('loss', avg_loss.result(), step=optimizer.iterations) avg_loss.reset_states() def test(model, test_x, test_y, step_num): # training=False is only needed if there are layers with different # behavior during training versus inference (e.g. Dropout). loss = loss_fn(model(test_x, training=False), test_y) tf.summary.scalar('loss', loss, step=step_num) train_summary_writer = tf.summary.create_file_writer('/tmp/summaries/train') test_summary_writer = tf.summary.create_file_writer('/tmp/summaries/test') with train_summary_writer.as_default(): train(model, optimizer, dataset) with test_summary_writer.as_default(): test(model, test_x, test_y, optimizer.iterations)

Visualice los resúmenes apuntando TensorBoard al directorio de registros de resumen:

tensorboard --logdir /tmp/summaries

Use la API tf.summary para escribir los datos de resumen para la visualización en TensorBoard. Para más información, lea la guía de tf.summary.

# Create the metrics loss_metric = tf.keras.metrics.Mean(name='train_loss') accuracy_metric = tf.keras.metrics.SparseCategoricalAccuracy(name='train_accuracy') @tf.function def train_step(inputs, labels): with tf.GradientTape() as tape: predictions = model(inputs, training=True) regularization_loss=tf.math.add_n(model.losses) pred_loss=loss_fn(labels, predictions) total_loss=pred_loss + regularization_loss gradients = tape.gradient(total_loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables)) # Update the metrics loss_metric.update_state(total_loss) accuracy_metric.update_state(labels, predictions) for epoch in range(NUM_EPOCHS): # Reset the metrics loss_metric.reset_states() accuracy_metric.reset_states() for inputs, labels in train_data: train_step(inputs, labels) # Get the metric results mean_loss=loss_metric.result() mean_accuracy = accuracy_metric.result() print('Epoch: ', epoch) print(' loss: {:.3f}'.format(mean_loss)) print(' accuracy: {:.3f}'.format(mean_accuracy))

Nombres de métricas de Keras

Los modelos Keras conservan consistencia con respecto a la administración de los nombres de las métricas. Cuando se pasa una cadena de caracteres (string) en la lista de métricas, esa cadena exacta se usa como el name de la métrica. Estos nombres se ven en el objeto de historia que devuelve model.fit y en los registros pasados a keras.callbacks. Se establece a la cadena que se pasó en la lista de métricas.

model.compile( optimizer = tf.keras.optimizers.Adam(0.001), loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics = ['acc', 'accuracy', tf.keras.metrics.SparseCategoricalAccuracy(name="my_accuracy")]) history = model.fit(train_data)
history.history.keys()

Depuración

Use la ejecución eager para correr el código paso a paso para inspeccionar formas, tipos de datos y valores. Ciertas API, como tf.function, tf.keras, etc. están diseñadas para usar ejecución de Graph (grafos) por motivos de mejor desempeño y portabilidad. Cuando realice la depuración, use tf.config.run_functions_eagerly(True) para aplicar la ejecución eager dentro de este código.

Por ejemplo:

@tf.function def f(x): if x > 0: import pdb pdb.set_trace() x = x + 1 return x tf.config.run_functions_eagerly(True) f(tf.constant(1))
>>> f() -> x = x + 1 (Pdb) l 6 @tf.function 7 def f(x): 8 if x > 0: 9 import pdb 10 pdb.set_trace() 11 -> x = x + 1 12 return x 13 14 tf.config.run_functions_eagerly(True) 15 f(tf.constant(1)) [EOF]

Esto también funciona dentro de los modelos Keras y de otras API compatibles con la ejecución eager:

class CustomModel(tf.keras.models.Model): @tf.function def call(self, input_data): if tf.reduce_mean(input_data) > 0: return input_data else: import pdb pdb.set_trace() return input_data // 2 tf.config.run_functions_eagerly(True) model = CustomModel() model(tf.constant([-2, -4]))
>>> call() -> return input_data // 2 (Pdb) l 10 if tf.reduce_mean(input_data) > 0: 11 return input_data 12 else: 13 import pdb 14 pdb.set_trace() 15 -> return input_data // 2 16 17 18 tf.config.run_functions_eagerly(True) 19 model = CustomModel() 20 model(tf.constant([-2, -4]))

Notas:

  • Los métodos tf.keras.Model como fit, evaluate y predict ejecutan graphs con tf.function en su funcionamiento interno.

  • Cuando use tf.keras.Model.compile, establezca run_eagerly = True para deshabilitar que la lógica Model se encapsule en tf.function.

  • Use tf.data.experimental.enable_debug_mode para habilitar el modo de depuración para tf.data. Para más detalles, lea los documentos de la API.

No mantenga tf.Tensors en los objetos

Estos objetos de tensores pueden crearse en un tf.function o en el contexto eager, entonces, estos tensores se comportan de un modo diferente. Siempre use los tf.Tensor solamente para valores intermedios.

Para dar seguimiento al estado, use las tf.Variable, ya que siempre se pueden usar desde cualquiera de los dos contextos. Para más información, lea la guía de tf.Variable.

Recursos y lecturas complementarias