En la lección anterior entrenamos una red completa con las herramientas más básicas posibles: medimos el error con el cuadrado de la diferencia y corregimos con descenso de gradiente puro sobre todos los datos a la vez. Funcionó, pero ambas elecciones eran provisionales. Esta lección las examina a fondo, porque son dos de las decisiones de diseño más importantes de cualquier proyecto: la función de pérdida define qué significa "equivocarse" (y debe casar con el tipo de problema y con la activación de salida que elegiste en 02-02), y el optimizador define cómo se usa el gradiente para corregir (y determina si tu entrenamiento tarda minutos u horas, o si directamente no converge). Veremos las pérdidas estándar con fórmulas e intuición, las tres variantes del descenso de gradiente, las patologías del learning rate, y los optimizadores modernos —momentum, RMSprop y Adam— que usarás en la práctica. Cerramos viendo cómo todo esto se declara en Keras con una sola línea: compile().

Contenido

  1. Qué es exactamente una función de pérdida
  2. Pérdidas para regresión: MSE y MAE
  3. Pérdidas para clasificación: entropía cruzada binaria y categórica
  4. Tabla de decisión: qué pérdida para qué problema
  5. Descenso de gradiente: batch, estocástico y mini-batch
  6. El learning rate y sus patologías
  7. Optimizadores modernos: momentum, RMSprop y Adam
  8. Todo junto en Keras: compile()

Qué es exactamente una función de pérdida

La función de pérdida (loss) toma la predicción $\hat{y}$ y la etiqueta real $y$ y devuelve un solo número: cuánto de mal lo ha hecho la red en ese ejemplo (o, promediando, en un batch). Todo el aprendizaje descrito en la lección de backpropagation empieza derivando ese número; por eso la pérdida debe ser derivable y debe penalizar de forma sensata los errores del problema concreto.

No es un detalle técnico: la pérdida es el contrato que le das a la red. Si el contrato está mal elegido, la red optimizará diligentemente la cosa equivocada. La buena noticia es que para los tres tipos de problema estándar (regresión, clasificación binaria, clasificación multiclase) hay respuestas canónicas.

Pérdidas para regresión: MSE y MAE

Para predecir números continuos —la demanda semanal de cafeteras de TecnoMarket— las dos pérdidas básicas comparan predicción y realidad sobre los $m$ ejemplos:

Error cuadrático medio (MSE, Mean Squared Error):

$$\text{MSE} = \frac{1}{m}\sum_{i=1}^{m} (\hat{y}_i - y_i)^2$$

Error absoluto medio (MAE, Mean Absolute Error):

$$\text{MAE} = \frac{1}{m}\sum_{i=1}^{m} |\hat{y}_i - y_i|$$

La diferencia está en cómo tratan los errores grandes. Al elevar al cuadrado, el MSE castiga desproporcionadamente los fallos gordos: equivocarse en 10 unidades pesa 100 veces más que equivocarse en 1 (no 10 veces más). El MAE trata cada unidad de error por igual.

Consecuencia práctica con TecnoMarket: supón que la demanda real de una semana atípica (Black Friday) fue 500 unidades y tu histórico normal ronda 50. Con MSE, ese único punto extremo domina la pérdida total y la red deformará sus predicciones normales para no fallar tanto ahí; con MAE, el punto pesa lo justo. Regla práctica:

  • MSE por defecto: gradientes suaves, entrenamiento estable, y penalizar fuerte los errores grandes suele ser lo deseable.
  • MAE cuando tus datos tienen valores atípicos (outliers) que no quieres que secuestren el entrenamiento.
import numpy as np

y_real = np.array([48, 52, 45, 500])   # demanda real; la ultima semana fue Black Friday
y_pred = np.array([50, 50, 50, 60])    # prediccion de un modelo "normal"

mse = np.mean((y_pred - y_real) ** 2)  # -> 48405.25  (el outlier lo domina todo)
mae = np.mean(np.abs(y_pred - y_real)) # -> 112.25    (mas representativo del dia a dia)

Pérdidas para clasificación: entropía cruzada binaria y categórica

Para clasificar podríamos usar MSE ("la probabilidad predicha menos la etiqueta, al cuadrado", como hicimos provisionalmente en la lección anterior), pero existe una pérdida mucho mejor adaptada a salidas que son probabilidades: la entropía cruzada (cross-entropy).

Entropía cruzada binaria (BCE) — para salida sigmoide con etiquetas 0/1:

$$\text{BCE} = -\frac{1}{m}\sum_{i=1}^{m} \Big[ y_i \log \hat{y}_i + (1-y_i)\log(1-\hat{y}_i) \Big]$$

La fórmula asusta menos de lo que parece, porque para cada ejemplo solo sobrevive uno de los dos sumandos:

  • Si $y = 1$ (era fraude), la pérdida es $-\log \hat{y}$: vale casi 0 si la red dijo $\hat{y} \approx 1$ (acierto seguro) y tiende a infinito si dijo $\hat{y} \approx 0$ (error con total confianza).
  • Si $y = 0$, simétricamente, la pérdida es $-\log(1-\hat{y})$.

Esa es la intuición clave: la entropía cruzada castiga brutalmente la confianza equivocada. Decir "2 % de probabilidad de fraude" en un pedido que era fraude cuesta $-\log(0.02) \approx 3.9$; decir "40 %" solo cuesta $0.92$. Con MSE la diferencia sería mucho más tibia (0.96 frente a 0.36), y además MSE + sigmoide produce gradientes diminutos justo cuando la red está más equivocada (por la saturación que vimos en 02-02); la pareja sigmoide + BCE cancela ese problema y aprende rápido precisamente en los errores graves.

Entropía cruzada categórica (CCE) — para salida softmax con $K$ clases:

$$\text{CCE} = -\frac{1}{m}\sum_{i=1}^{m} \log \hat{y}_{i,c_i}$$

donde $\hat{y}_{i,c_i}$ es la probabilidad que la red asignó a la clase correcta del ejemplo $i$. Lectura directa: la pérdida solo mira cuánta probabilidad diste a la respuesta buena. Si el clasificador de fotos de TecnoMarket ve una cafetera y su softmax asigna (portátil 0.05, cafetera 0.90, aspiradora 0.03, monitor 0.02), la pérdida es $-\log(0.90) = 0.105$: bien. Si asignó cafetera 0.10, la pérdida es $-\log(0.10) = 2.30$: castigo serio.

En Keras verás dos variantes de la CCE según el formato de las etiquetas: categorical_crossentropy si son one-hot ([0,1,0,0]) y sparse_categorical_crossentropy si son enteros (1). Son la misma matemática con distinta codificación de entrada; la variante sparse nos ahorrará un paso de conversión en la próxima lección.

Tabla de decisión: qué pérdida para qué problema

Esta tabla completa la de activaciones de salida de 02-02 — cada fila es la pareja activación + pérdida que va junta:

Problema Ejemplo TecnoMarket Activación de salida Pérdida Nombre en Keras
Regresión Predecir demanda semanal de un producto Ninguna (lineal) MSE (o MAE con outliers) "mse" / "mae"
Clasificación binaria ¿Pedido fraudulento? ¿Reseña positiva? Sigmoide (1 neurona) Entropía cruzada binaria "binary_crossentropy"
Multiclase (etiquetas one-hot) Foto → 1 de 12 categorías de producto Softmax (K neuronas) Entropía cruzada categórica "categorical_crossentropy"
Multiclase (etiquetas enteras) Igual, con etiquetas 0..11 Softmax (K neuronas) CCE dispersa "sparse_categorical_crossentropy"
Multietiqueta Reseña → temas {envío, precio, calidad} Sigmoide (K neuronas) BCE sobre cada salida "binary_crossentropy"

Descenso de gradiente: batch, estocástico y mini-batch

En la lección anterior calculamos el gradiente usando los 400 pedidos a la vez en cada actualización. Esa es una de tres estrategias posibles, que se diferencian en cuántos ejemplos miran antes de cada corrección:

Variante Ejemplos por actualización Ventajas Inconvenientes
Batch (por lotes completo) Todos ($m$) Gradiente exacto, trayectoria suave Lentísimo y prohibitivo en memoria con datasets grandes; 1 sola actualización por época
Estocástico (SGD puro) 1 Actualizaciones baratas y frecuentes; el ruido ayuda a escapar de malos rincones Trayectoria muy errática; desaprovecha la vectorización de la GPU
Mini-batch Un lote de 32–256 Equilibrio: gradiente razonable, aprovecha la GPU, muchas actualizaciones por época Hay que elegir el tamaño de batch

La intuición con TecnoMarket: para ajustar la política antifraude podrías esperar a analizar todos los pedidos del año (batch: decisión muy informada, una vez al año), reaccionar tras cada pedido individual (estocástico: rapidísimo pero histérico, un solo pedido raro te hace bandazos), o revisar cada mañana el lote de pedidos del día anterior (mini-batch: frecuente y estable). El estándar absoluto en deep learning es mini-batch, y es lo que el parámetro batch_size de Keras controla — el mismo "batch" del vocabulario de 01-04. Nota terminológica: en la práctica, cuando alguien dice "SGD" casi siempre se refiere a mini-batch SGD.

Con mini-batches, una época ya no es una actualización sino muchas: con 60 000 ejemplos y batch_size=32, cada época son 1 875 actualizaciones de pesos.

El learning rate y sus patologías

El learning rate $\eta$ multiplica al gradiente en cada actualización: $w \leftarrow w - \eta \nabla L$. Ya lo conoces desde la regla del perceptrón y el grifo de la ducha; ahora, sus modos de fallo. Imagina la pérdida como un valle y a ti descendiendo a ciegas dando pasos de longitud $\eta$:

  • $\eta$ demasiado grande: saltas de una ladera a la opuesta. La pérdida oscila o incluso diverge (crece hasta nan, como viste en el ejercicio 3 de la lección anterior).
  • $\eta$ algo grande: bajas rápido al principio pero luego rebotas alrededor del fondo sin afinar: la pérdida se estanca en un valor mediocre y ruidoso.
  • $\eta$ demasiado pequeño: cada paso es milimétrico. La pérdida baja de forma bonita y monótona… y tras horas sigue lejos del fondo. Además puedes quedarte atascado en el primer rellano que encuentres.
  • $\eta$ adecuado: descenso rápido al principio que se va asentando. En la práctica se encuentra probando potencias de 10 (0.1, 0.01, 0.001…) y mirando la curva de pérdida.

Un truco clásico es reducir $\eta$ durante el entrenamiento (pasos grandes al principio, finos al final). Los optimizadores modernos del siguiente apartado automatizan en gran parte esta gestión.

Optimizadores modernos: momentum, RMSprop y Adam

El descenso de gradiente puro (SGD) usa en cada paso solo el gradiente actual. Los optimizadores modernos le añaden memoria para navegar mejor el valle de la pérdida.

Momentum: la bola que rueda

$$v \leftarrow \beta v - \eta \nabla L \qquad w \leftarrow w + v$$

En lugar de dar pasos independientes, mantenemos una velocidad $v$ que acumula los gradientes recientes ($\beta \approx 0.9$: cada paso conserva el 90 % del impulso anterior). Intuición: una bola pesada rodando ladera abajo. Dos beneficios: en direcciones donde el gradiente apunta consistentemente igual, la bola acelera; en direcciones donde el gradiente cambia de signo a cada paso (las oscilaciones de ladera a ladera), los impulsos opuestos se cancelan y la trayectoria se suaviza. Además, el impulso ayuda a atravesar pequeños rellanos y baches.

RMSprop: un learning rate a medida de cada parámetro

$$s \leftarrow \beta s + (1-\beta)(\nabla L)^2 \qquad w \leftarrow w - \frac{\eta}{\sqrt{s} + \epsilon} \nabla L$$

RMSprop lleva, para cada parámetro por separado, una media móvil $s$ del cuadrado de sus gradientes recientes, y divide el paso por su raíz. Efecto: los parámetros con gradientes históricamente enormes dan pasos moderados (se les frena) y los de gradientes minúsculos dan pasos relativamente mayores (se les anima). Es decir: deja de haber un único $\eta$ para 29 (o 29 millones de) parámetros con escalas distintas — cada uno recibe un paso adaptado.

Adam: momentum + RMSprop

Adam (Adaptive Moment Estimation) combina ambas ideas: mantiene la media móvil del gradiente (como momentum) y la media móvil de su cuadrado (como RMSprop), con una pequeña corrección de arranque, y las usa juntas. Sus hiperparámetros por defecto (learning_rate=0.001, $\beta_1=0.9$, $\beta_2=0.999$) funcionan bien en una enorme variedad de problemas, y por eso Adam es el optimizador por defecto con el que empezar cualquier proyecto.

Optimizador Idea añadida Memoria que guarda Cuándo usarlo
SGD Ninguna (base) Nada Docencia; producción con ajuste experto
SGD + momentum Inercia / velocidad 1 valor por parámetro Clásico en visión, muy buen resultado final bien ajustado
RMSprop Paso adaptado por parámetro 1 valor por parámetro Histórico en redes recurrentes (módulo 4)
Adam Momentum + adaptación 2 valores por parámetro Por defecto: robusto sin apenas ajuste

Matiz honesto: Adam converge rápido "sin tocar nada", pero un SGD+momentum finamente ajustado a veces alcanza soluciones ligeramente mejores en visión. Para este curso: empieza siempre con Adam; considera alternativas solo cuando tengas un motivo.

Todo junto en Keras: compile()

Todo lo anterior se declara en Keras en una sola llamada, el paso compile() que convierte una arquitectura en un modelo entrenable. No vamos a construir aún el modelo completo (eso es la próxima lección), solo a leer esta línea con ojos nuevos:

from tensorflow import keras

# Deteccion de fraude (binaria): sigmoide en la salida + BCE + Adam
modelo.compile(
    optimizer="adam",                  # el optimizador del apartado 7
    loss="binary_crossentropy",        # la perdida de la tabla de decision
    metrics=["accuracy"],              # metricas SOLO para observar, no se optimizan
)

# Variante con hiperparametros explicitos:
modelo.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.001),
    loss="binary_crossentropy",
    metrics=["accuracy"],
)

# Otros dos proyectos de TecnoMarket, misma estructura:
# - Clasificador de fotos (12 clases, etiquetas enteras):
#     optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]
# - Prediccion de demanda (regresion):
#     optimizer="adam", loss="mse", metrics=["mae"]

Puntos que debes tener claros al leerlo:

  • loss es lo que se optimiza; metrics es lo que se observa. El accuracy no es derivable (es un recuento de aciertos), así que no puede ser la pérdida; se muestra para que los humanos sigamos el progreso.
  • La cadena "adam" usa los valores por defecto; el objeto keras.optimizers.Adam(...) permite ajustar el learning rate cuando haga falta.
  • El batch_size (mini-batch) no va en compile() sino en fit(), junto con las épocas — lo veremos en acción en la próxima lección.
  • La coherencia activación-de-salida ↔ pérdida es responsabilidad tuya: Keras no te avisará si emparejas softmax con binary_crossentropy; simplemente entrenará mal.

Errores Comunes y Consejos

  • Emparejar mal salida y pérdida. Los tres emparejamientos válidos son: lineal+MSE/MAE, sigmoide+BCE, softmax+CCE. Cualquier otra combinación (softmax con BCE, sigmoide con CCE…) entrena raro o directamente mal, a menudo sin dar error explícito.
  • categorical_crossentropy con etiquetas enteras. Si tus etiquetas son 0..K-1 (no one-hot) y usas la CCE normal, Keras lanza un error de formas o aprende basura. Usa sparse_categorical_crossentropy o convierte con keras.utils.to_categorical.
  • Optimizar el accuracy directamente. No se puede: no es derivable. La pérdida es el sustituto derivable; acepta que a veces la pérdida baja sin que el accuracy se mueva (la red gana confianza en aciertos que ya tenía).
  • Batch demasiado grande "porque va más rápido". Cada época tiene menos actualizaciones y el gradiente pierde el ruido beneficioso; además puede agotar la memoria de la GPU. Empieza en 32 o 64.
  • Cambiar de optimizador antes que de learning rate. Si el entrenamiento va mal, lo primero que hay que tocar es $\eta$ (prueba ÷10 y ×10); cambiar SGD por Adam sin revisar $\eta$ es tratar el síntoma.
  • Comparar pérdidas entre problemas distintos. Un MSE de 0.05 y una BCE de 0.05 no son comparables ni "buenos" en abstracto; la pérdida solo tiene sentido comparada consigo misma a lo largo del entrenamiento (y con una línea base tonta, como predecir siempre la media).

Ejercicios

  1. Entropía cruzada a mano. El detector de fraude evalúa 4 pedidos con etiquetas reales y = [1, 0, 1, 0] y predice probabilidades y_hat = [0.9, 0.2, 0.3, 0.95]. Calcula la BCE total (media de los 4) con numpy y a mano término a término. ¿Qué pedido aporta más pérdida y por qué?
  2. Elección razonada. Para cada caso de TecnoMarket, indica activación de salida, pérdida (nombre de Keras) y una métrica razonable: (a) estimar el tiempo de entrega en días de un pedido; (b) clasificar tickets de soporte en {facturación, envío, garantía, otros}; (c) decidir si mostrar una oferta a un cliente (sí/no); (d) predecir el precio de recompra de móviles usados sabiendo que hay tasaciones atípicas ocasionales.
  3. Carrera de optimizadores. Reutiliza la red numpy 3-8-1 de la lección anterior y añade momentum a la actualización (guarda una velocidad vW1, vb1, vW2, vb2 inicializada a ceros y aplica $v = 0.9v - \eta \nabla$; $w = w + v$). Entrena 3000 épocas con SGD puro y con momentum usando la misma $\eta = 0.5$ y compara la pérdida en las épocas 100, 500 y 1000.

Soluciones

Ejercicio 1.

y     = np.array([1, 0, 1, 0])
y_hat = np.array([0.9, 0.2, 0.3, 0.95])
bce = -np.mean(y*np.log(y_hat) + (1-y)*np.log(1-y_hat))   # -> 1.135

Término a término: $-\log(0.9)=0.105$; $-\log(1-0.2)=0.223$; $-\log(0.3)=1.204$; $-\log(1-0.95)=2.996$. Media ≈ 1.13. El que más aporta es el cuarto pedido (pérdida ≈ 3.0): la red dijo "95 % fraude" y era legítimo — confianza alta equivocada, justo lo que la entropía cruzada castiga con más dureza (más incluso que el tercer pedido, que también falla pero con menos convicción).

Ejercicio 2. (a) Regresión: salida lineal, loss="mse", métrica mae (interpretable en días). (b) Multiclase de 4 categorías: softmax de 4 neuronas, sparse_categorical_crossentropy (etiquetas enteras), métrica accuracy. (c) Binaria: 1 sigmoide, binary_crossentropy, accuracy. (d) Regresión con outliers declarados: salida lineal, loss="mae" (robusta frente a tasaciones atípicas), métrica mae.

Ejercicio 3. Cambios mínimos en el bucle de entrenamiento:

vW1 = np.zeros_like(W1); vb1 = np.zeros_like(b1)
vW2 = np.zeros_like(W2); vb2 = np.zeros_like(b2)
# ... tras calcular dW1, db1, dW2, db2 en el backward:
vW1 = 0.9*vW1 - eta*dW1;  W1 += vW1
vb1 = 0.9*vb1 - eta*db1;  b1 += vb1
vW2 = 0.9*vW2 - eta*dW2;  W2 += vW2
vb2 = 0.9*vb2 - eta*db2;  b2 += vb2

Resultado típico: con momentum la pérdida en la época 100 ya está donde el SGD puro llega hacia la 400–600; en la época 1000 ambos se acercan al mismo valor final, pero momentum llegó mucho antes. (Si con momentum la pérdida oscila al principio, es la inercia acumulando demasiado impulso: baja $\eta$ a 0.1 y compara de nuevo — buen ejemplo de que optimizador y learning rate se ajustan juntos.)

Conclusión

Ya tienes las dos decisiones de entrenamiento bajo control. La función de pérdida traduce "equivocarse" a un número derivable, y se elige por el tipo de problema formando pareja con la activación de salida: lineal+MSE/MAE para regresión, sigmoide+BCE para binaria, softmax+CCE para multiclase. El optimizador decide cómo usar el gradiente: mini-batch como estrategia universal de datos, learning rate como el hiperparámetro más delicado, y Adam (momentum + adaptación por parámetro) como punto de partida robusto. Y has visto que en Keras todo esto se declara en una línea de compile().

Con esto, el módulo ha completado todas las piezas: neurona y capas (02-01), activaciones (02-02), forward y backward (02-03), pérdidas y optimizadores (02-04). En la próxima lección las ensamblamos todas: construirás, entrenarás y evaluarás en Keras tu primera red neuronal completa sobre un dataset real de imágenes, siguiendo la metodología del curso — prototipo público primero, TecnoMarket después.

Curso de Deep Learning

Módulo 1: Introducción a Deep Learning

Módulo 2: Fundamentos de Redes Neuronales

Módulo 3: Redes Neuronales Convolucionales (CNN)

Módulo 4: Redes Neuronales Recurrentes (RNN)

Módulo 5: Técnicas Avanzadas en Deep Learning

Módulo 6: Herramientas y Frameworks

Módulo 7: Proyectos Prácticos

Módulo 8: Consideraciones Éticas y Futuro del Deep Learning

© Copyright 2026. Todos los derechos reservados