Funciones de pérdida y métricas en TensorFlow

Intermedio
TensorFlow
TensorFlow
Actualizado: 18/04/2026

¿Por qué importa elegir bien la función de pérdida?

La función de pérdida (loss function) cuantifica la diferencia entre las predicciones del modelo y los valores reales. Es el objetivo que el optimizador minimiza durante el entrenamiento. Elegir la pérdida equivocada puede hacer que el modelo converja lentamente, prediga valores incorrectos o directamente no aprenda.

Las métricas son indicadores adicionales que se calculan durante el entrenamiento para monitorizar el progreso pero que no intervienen en la optimización.

Funciones de pérdida para regresión

import tensorflow as tf
import numpy as np

# Datos de ejemplo
y_real = tf.constant([1.0, 2.0, 3.0, 4.0, 5.0])
y_pred = tf.constant([1.1, 1.9, 3.2, 3.8, 5.3])

# Mean Squared Error (MSE): penaliza más los errores grandes
mse = tf.keras.losses.MeanSquaredError()
print(f"MSE: {mse(y_real, y_pred).numpy():.4f}")

# Root Mean Squared Error (RMSE): misma escala que y
rmse = tf.sqrt(mse(y_real, y_pred))
print(f"RMSE: {rmse.numpy():.4f}")

# Mean Absolute Error (MAE): más robusto a outliers
mae = tf.keras.losses.MeanAbsoluteError()
print(f"MAE: {mae(y_real, y_pred).numpy():.4f}")

# Huber Loss: combinación MSE/MAE, robusta a outliers con transición suave
huber = tf.keras.losses.Huber(delta=1.0)
print(f"Huber: {huber(y_real, y_pred).numpy():.4f}")

# Mean Absolute Percentage Error (MAPE): error relativo en %
mape = tf.keras.losses.MeanAbsolutePercentageError()
print(f"MAPE: {mape(y_real, y_pred).numpy():.4f}%")

Guía de selección para regresión:

| Situación | Función de pérdida recomendada | |---|---| | Sin outliers | MSE | | Con outliers moderados | Huber | | Con muchos outliers | MAE | | Comparación relativa (%) | MAPE |

Funciones de pérdida para clasificación binaria

import tensorflow as tf
import numpy as np

# Etiquetas reales (0 o 1) y probabilidades predichas [0, 1]
y_real = tf.constant([1.0, 0.0, 1.0, 1.0, 0.0])
y_pred = tf.constant([0.9, 0.1, 0.8, 0.3, 0.2])

# Binary Cross-Entropy: estándar para clasificación binaria
bce = tf.keras.losses.BinaryCrossentropy()
print(f"Binary Crossentropy: {bce(y_real, y_pred).numpy():.4f}")

# Hinge Loss: usada con SVM y redes con activación tanh (-1, 1)
hinge = tf.keras.losses.Hinge()
y_real_hinge = tf.constant([-1.0, 1.0, -1.0, -1.0, 1.0])  # -1 y 1
y_pred_hinge = tf.constant([-0.8, 0.9, -0.5, 0.3, 0.8])
print(f"Hinge: {hinge(y_real_hinge, y_pred_hinge).numpy():.4f}")

Funciones de pérdida para clasificación multiclase

import tensorflow as tf
import numpy as np

# Etiquetas como enteros
y_real_int = tf.constant([2, 0, 1, 2, 1])
# Predicciones: vector de probabilidades por clase (softmax aplicado)
y_pred_prob = tf.constant([
    [0.1, 0.2, 0.7],  # clase 2
    [0.8, 0.1, 0.1],  # clase 0
    [0.1, 0.7, 0.2],  # clase 1
    [0.2, 0.1, 0.7],  # clase 2
    [0.1, 0.6, 0.3]   # clase 1
])

# Sparse Categorical Crossentropy: etiquetas como enteros
scce = tf.keras.losses.SparseCategoricalCrossentropy()
print(f"Sparse CCE: {scce(y_real_int, y_pred_prob).numpy():.4f}")

# Categorical Crossentropy: etiquetas en one-hot
y_real_onehot = tf.one_hot(y_real_int, depth=3)
cce = tf.keras.losses.CategoricalCrossentropy()
print(f"Categorical CCE: {cce(y_real_onehot, y_pred_prob).numpy():.4f}")

# Kullback-Leibler Divergence: para distribuciones de probabilidad
kld = tf.keras.losses.KLDivergence()
print(f"KL Divergence: {kld(y_real_onehot, y_pred_prob).numpy():.4f}")

Métricas estándar en Keras

import tensorflow as tf

modelo = tf.keras.Sequential([
    tf.keras.layers.Dense(64, activation='relu', input_shape=(20,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

modelo.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=[
        tf.keras.metrics.BinaryAccuracy(name='accuracy'),
        tf.keras.metrics.AUC(name='auc'),
        tf.keras.metrics.Precision(name='precision'),
        tf.keras.metrics.Recall(name='recall'),
        tf.keras.metrics.TruePositives(name='tp'),
        tf.keras.metrics.FalsePositives(name='fp'),
        tf.keras.metrics.TrueNegatives(name='tn'),
        tf.keras.metrics.FalseNegatives(name='fn')
    ]
)

modelo.summary()

Para clasificación multiclase:

import tensorflow as tf

modelo_mc = tf.keras.Sequential([
    tf.keras.layers.Dense(128, activation='relu', input_shape=(50,)),
    tf.keras.layers.Dense(10, activation='softmax')
])

modelo_mc.compile(
    optimizer='adam',
    loss='sparse_categorical_crossentropy',
    metrics=[
        'accuracy',
        tf.keras.metrics.TopKCategoricalAccuracy(k=3, name='top3_accuracy'),
        tf.keras.metrics.SparseCategoricalAccuracy(name='sparse_acc')
    ]
)

Función de pérdida personalizada

import tensorflow as tf

# --- Pérdida personalizada como función ---
def focal_loss(gamma=2.0, alpha=0.25):
    """Focal loss para clases muy desbalanceadas."""
    def loss_fn(y_true, y_pred):
        y_pred = tf.clip_by_value(y_pred, 1e-7, 1 - 1e-7)
        cross_entropy = -y_true * tf.math.log(y_pred)
        peso = alpha * tf.pow(1 - y_pred, gamma)
        focal = peso * cross_entropy
        return tf.reduce_mean(tf.reduce_sum(focal, axis=-1))
    return loss_fn

# Usar en compile
modelo = tf.keras.Sequential([
    tf.keras.layers.Dense(32, activation='relu', input_shape=(10,)),
    tf.keras.layers.Dense(3, activation='softmax')
])
modelo.compile(
    optimizer='adam',
    loss=focal_loss(gamma=2.0, alpha=0.25),
    metrics=['accuracy']
)
print("Modelo con focal loss compilado.")
import tensorflow as tf

# --- Pérdida personalizada como clase ---
class WeightedBinaryCrossentropy(tf.keras.losses.Loss):
    """Binary crossentropy con peso diferente para cada clase."""

    def __init__(self, peso_clase_positiva=2.0, **kwargs):
        super().__init__(**kwargs)
        self.peso_clase_positiva = peso_clase_positiva

    def call(self, y_true, y_pred):
        y_pred = tf.clip_by_value(y_pred, 1e-7, 1 - 1e-7)
        bce = -(y_true * tf.math.log(y_pred) * self.peso_clase_positiva +
                (1 - y_true) * tf.math.log(1 - y_pred))
        return tf.reduce_mean(bce)

    def get_config(self):
        config = super().get_config()
        config.update({'peso_clase_positiva': self.peso_clase_positiva})
        return config

modelo_wbce = tf.keras.Sequential([
    tf.keras.layers.Dense(32, activation='relu', input_shape=(10,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
modelo_wbce.compile(
    optimizer='adam',
    loss=WeightedBinaryCrossentropy(peso_clase_positiva=3.0),
    metrics=['accuracy']
)
print("Modelo con pérdida ponderada compilado.")

Métrica personalizada

import tensorflow as tf

class F1Score(tf.keras.metrics.Metric):
    """F1-Score personalizado para clasificación binaria."""

    def __init__(self, name='f1_score', **kwargs):
        super().__init__(name=name, **kwargs)
        self.verdaderos_positivos = self.add_weight(name='tp', initializer='zeros')
        self.falsos_positivos = self.add_weight(name='fp', initializer='zeros')
        self.falsos_negativos = self.add_weight(name='fn', initializer='zeros')

    def update_state(self, y_true, y_pred, sample_weight=None):
        y_pred_bin = tf.cast(y_pred >= 0.5, tf.float32)
        y_true = tf.cast(y_true, tf.float32)

        self.verdaderos_positivos.assign_add(
            tf.reduce_sum(y_true * y_pred_bin)
        )
        self.falsos_positivos.assign_add(
            tf.reduce_sum((1 - y_true) * y_pred_bin)
        )
        self.falsos_negativos.assign_add(
            tf.reduce_sum(y_true * (1 - y_pred_bin))
        )

    def result(self):
        precision = self.verdaderos_positivos / (
            self.verdaderos_positivos + self.falsos_positivos + tf.keras.backend.epsilon()
        )
        recall = self.verdaderos_positivos / (
            self.verdaderos_positivos + self.falsos_negativos + tf.keras.backend.epsilon()
        )
        return 2 * precision * recall / (precision + recall + tf.keras.backend.epsilon())

    def reset_state(self):
        self.verdaderos_positivos.assign(0)
        self.falsos_positivos.assign(0)
        self.falsos_negativos.assign(0)

# Usar la métrica personalizada
modelo = tf.keras.Sequential([
    tf.keras.layers.Dense(32, activation='relu', input_shape=(15,)),
    tf.keras.layers.Dense(1, activation='sigmoid')
])
modelo.compile(
    optimizer='adam',
    loss='binary_crossentropy',
    metrics=['accuracy', F1Score()]
)
print("Modelo con F1Score personalizado compilado.")

Resumen: tabla de selección

| Problema | Función de pérdida | Métrica principal | |---|---|---| | Regresión | MSE / MAE / Huber | MAE, RMSE | | Clasificación binaria | BinaryCrossentropy | Accuracy, AUC, F1 | | Clasificación multiclase (enteros) | SparseCategoricalCrossentropy | Accuracy, Top-K Accuracy | | Clasificación multiclase (one-hot) | CategoricalCrossentropy | Accuracy | | Clases desbalanceadas | FocalLoss / BinaryCrossentropy ponderada | AUC, F1, Recall |

Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TensorFlow es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de TensorFlow

Explora más contenido relacionado con TensorFlow y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

Seleccionar la función de pérdida correcta según el tipo de problema (regresión, clasificación binaria, multiclase). Usar métricas estándar como accuracy, AUC, Precisión, Recall y F1. Implementar funciones de pérdida personalizadas. Crear métricas personalizadas heredando de tf.keras.metrics.Metric. Interpretar los valores de pérdida y métricas durante el entrenamiento.