TensorFlow: Entrenamiento y evaluación de modelos

Descubre las mejores prácticas para entrenar y evaluar modelos neuronales en TensorFlow. Aprende a configurar optimizadores, funciones de pérdida, callbacks, y estrategias de validación para maximizar la precisión de tus redes neuronales y evitar problema

Aprende TensorFlow GRATIS y certifícate

El proceso de entrenamiento y evaluación representa el núcleo del desarrollo de modelos de aprendizaje profundo. En esta sección exploraremos en detalle cómo configurar, ejecutar y supervisar el entrenamiento de redes neuronales en TensorFlow, así como las técnicas más efectivas para evaluar su rendimiento.

TensorFlow proporciona herramientas robustas para implementar ciclos de entrenamiento, desde opciones de alto nivel hasta mecanismos personalizados que permiten un control granular sobre cada aspecto del proceso. Dominar estos conceptos es esencial para desarrollar modelos que no solo aprendan efectivamente sino que también generalicen bien a datos no vistos.

El ciclo de entrenamiento en TensorFlow

El entrenamiento de modelos en TensorFlow puede implementarse mediante dos enfoques principales: utilizando la API de alto nivel con model.fit() o creando bucles de entrenamiento personalizados con tf.GradientTape().

Entrenamiento con model.fit()

El método fit() proporciona una interfaz simplificada que maneja automáticamente la propagación hacia adelante, el cálculo de la pérdida y la retropropagación:

model = tf.keras.Sequential([
    tf.keras.layers.Dense(128, activation='relu', input_shape=(784,)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

model.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=['accuracy']
)

history = model.fit(
    x_train, y_train,
    epochs=10,
    batch_size=32,
    validation_data=(x_val, y_val),
    verbose=1
)

Este método ofrece parámetros adicionales para personalizar el proceso:

  • shuffle: Controla si los datos se mezclan antes de cada época
  • callbacks: Lista de callbacks para monitorear y modificar el entrenamiento
  • class_weight: Diccionario para asignar pesos a clases desequilibradas
  • sample_weight: Pesos por muestra para priorizar ciertos ejemplos

Bucles de entrenamiento personalizados

Para casos que requieren mayor flexibilidad, podemos implementar bucles de entrenamiento utilizando tf.GradientTape():

# Definir modelo, optimizador y función de pérdida
model = tf.keras.Sequential([
    tf.keras.layers.Dense(128, activation='relu', input_shape=(784,)),
    tf.keras.layers.Dense(10, activation='softmax')
])

optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
loss_fn = tf.keras.losses.SparseCategoricalCrossentropy()

# Métricas para seguimiento
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()
val_accuracy = tf.keras.metrics.SparseCategoricalAccuracy()

# Preparación de datasets
train_dataset = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32)
val_dataset = tf.data.Dataset.from_tensor_slices((x_val, y_val)).batch(32)

# Bucle de entrenamiento
for epoch in range(5):
    # Reiniciar métricas
    train_accuracy.reset_states()
    
    # Ciclo de entrenamiento
    for x_batch, y_batch in train_dataset:
        with tf.GradientTape() as tape:
            # Propagación hacia adelante
            predictions = model(x_batch, training=True)
            # Cálculo de pérdida
            loss = loss_fn(y_batch, predictions)
        
        # Cálculo y aplicación de gradientes
        gradients = tape.gradient(loss, model.trainable_variables)
        optimizer.apply_gradients(zip(gradients, model.trainable_variables))
        
        # Actualizar métricas
        train_accuracy.update_state(y_batch, predictions)
    
    # Validación
    val_accuracy.reset_states()
    for x_batch, y_batch in val_dataset:
        predictions = model(x_batch, training=False)
        val_accuracy.update_state(y_batch, predictions)
    
    print(f"Epoch {epoch+1}: "
          f"Precisión entrenamiento: {train_accuracy.result().numpy():.4f}, "
          f"Precisión validación: {val_accuracy.result().numpy():.4f}")

Este enfoque permite:

  • Implementar lógicas personalizadas durante el entrenamiento
  • Modificar gradientes antes de aplicarlos
  • Calcular métricas intermedias
  • Implementar técnicas avanzadas como aprendizaje por currículum

Optimizadores

Los optimizadores determinan cómo se actualizan los pesos del modelo durante el entrenamiento en función de los gradientes calculados.

Tipos de optimizadores

TensorFlow ofrece varios optimizadores con características específicas:

  • SGD (Stochastic Gradient Descent): El optimizador clásico que puede incorporar momentum para acelerar la convergencia.
optimizer = tf.keras.optimizers.SGD(
    learning_rate=0.01,
    momentum=0.9,
    nesterov=True
)
  • Adam: Combina ideas de AdaGrad y RMSProp, adaptando las tasas de aprendizaje por parámetro y utilizando estimaciones del primer y segundo momento.
optimizer = tf.keras.optimizers.Adam(
    learning_rate=0.001,
    beta_1=0.9,    # Coeficiente de decaimiento para primer momento
    beta_2=0.999,  # Coeficiente de decaimiento para segundo momento
    epsilon=1e-07  # Constante para estabilidad numérica
)
  • RMSProp: Adapta las tasas de aprendizaje dividiendo por una media móvil de gradientes al cuadrado.
optimizer = tf.keras.optimizers.RMSprop(
    learning_rate=0.001,
    rho=0.9,       # Factor de decaimiento
    momentum=0.0,
    epsilon=1e-07
)

Programación de tasas de aprendizaje

La modificación de la tasa de aprendizaje durante el entrenamiento puede mejorar significativamente el rendimiento:

# Reducción al estancarse
reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(
    monitor='val_loss',
    factor=0.2,     # Factor de reducción
    patience=5,     # Épocas de espera antes de reducir
    min_lr=0.0001   # Tasa mínima
)

# Programación escalonada
lr_schedule = tf.keras.optimizers.schedules.PiecewiseConstantDecay(
    boundaries=[100, 200, 300],
    values=[1.0, 0.1, 0.01, 0.001]
)
optimizer = tf.keras.optimizers.Adam(learning_rate=lr_schedule)

# Decaimiento exponencial
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
    initial_learning_rate=0.1,
    decay_steps=10000,
    decay_rate=0.9,
    staircase=True   # Si True, produce decrementos escalonados
)
optimizer = tf.keras.optimizers.SGD(learning_rate=lr_schedule)

Funciones de pérdida

Las funciones de pérdida cuantifican la diferencia entre las predicciones del modelo y los valores reales, estableciendo el objetivo que el optimizador intentará minimizar.

Pérdidas para clasificación

  • Binary Crossentropy: Para problemas de clasificación binaria.
loss = tf.keras.losses.BinaryCrossentropy(from_logits=False)
  • Categorical Crossentropy: Para clasificación multiclase con etiquetas one-hot.
loss = tf.keras.losses.CategoricalCrossentropy(from_logits=False)
  • Sparse Categorical Crossentropy: Para clasificación multiclase con etiquetas enteras.
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)

Pérdidas para regresión

  • Mean Squared Error (MSE): Penaliza errores grandes cuadráticamente.
loss = tf.keras.losses.MeanSquaredError()
  • Mean Absolute Error (MAE): Menos sensible a valores atípicos.
loss = tf.keras.losses.MeanAbsoluteError()
  • Huber Loss: Combina MSE y MAE para mayor robustez.
loss = tf.keras.losses.Huber(delta=1.0)  # Delta controla la transición entre regímenes

Funciones de pérdida personalizadas

Para necesidades específicas, podemos implementar pérdidas personalizadas:

def focal_loss(gamma=2.0, alpha=0.25):
    """
    Implementa la pérdida focal que da mayor peso a ejemplos difíciles.
    Útil para clasificación con clases desequilibradas.
    
    Args:
        gamma: Factor de enfoque (higher -> más enfoque en ejemplos difíciles)
        alpha: Factor de balanceo para clases
    """
    def loss_function(y_true, y_pred):
        y_pred = tf.convert_to_tensor(y_pred)
        y_true = tf.cast(y_true, y_pred.dtype)
        
        # Calcular pérdida focal
        ce = tf.keras.backend.binary_crossentropy(y_true, y_pred)
        p_t = (y_true * y_pred) + ((1 - y_true) * (1 - y_pred))
        alpha_factor = y_true * alpha + (1 - y_true) * (1 - alpha)
        modulating_factor = tf.pow(1.0 - p_t, gamma)
        
        return tf.reduce_mean(alpha_factor * modulating_factor * ce)
    
    return loss_function

# Uso
model.compile(
    optimizer='adam',
    loss=focal_loss(gamma=2.0, alpha=0.25),
    metrics=['accuracy']
)

Métricas de evaluación

Las métricas proporcionan información cuantitativa sobre el rendimiento del modelo durante y después del entrenamiento.

Métricas para clasificación

  • Accuracy: Proporción de predicciones correctas.
metrics = [tf.keras.metrics.Accuracy()]
  • Precision: Proporción de predicciones positivas correctas.
metrics = [tf.keras.metrics.Precision()]
  • Recall: Proporción de positivos reales identificados correctamente.
metrics = [tf.keras.metrics.Recall()]
  • F1-Score: Media armónica de precisión y recall.
def f1_score(y_true, y_pred):
    """Implementación de F1 Score como métrica personalizada"""
    precision = tf.keras.metrics.Precision()(y_true, y_pred)
    recall = tf.keras.metrics.Recall()(y_true, y_pred)
    return 2 * ((precision * recall) / (precision + recall + tf.keras.backend.epsilon()))

metrics = ['accuracy', f1_score]
  • AUC: Área bajo la curva ROC.
metrics = [tf.keras.metrics.AUC()]

Métricas para regresión

  • MSE/MAE: Errores cuadráticos/absolutos medios.
metrics = [
    tf.keras.metrics.MeanSquaredError(),
    tf.keras.metrics.MeanAbsoluteError()
]
  • RMSE: Raíz del error cuadrático medio.
def rmse(y_true, y_pred):
    return tf.sqrt(tf.keras.metrics.mean_squared_error(y_true, y_pred))

metrics = [rmse]
  • : Coeficiente de determinación.
def r_squared(y_true, y_p
Empezar curso de TensorFlow

Lecciones de este módulo de TensorFlow

Lecciones de programación del módulo Entrenamiento y evaluación de modelos del curso de TensorFlow.