📖 Teoría

Entrenamiento de Redes Neuronales

Cómo aprende una red neuronal: desde el descenso del gradiente hasta la retropropagación. Domina el algoritmo que hace posible todo el deep learning moderno.

🎯 El problema de optimización

Entrenar una red neuronal es, en esencia, un problema de optimización. Tenemos una función de pérdida (o loss function) que mide lo mal que lo está haciendo nuestro modelo, y queremos encontrar los valores de los parámetros (pesos y biases) que minimizan esa función.

Formalmente, dado un dataset de entrenamiento \(\{(\mathbf{x}_i, y_i)\}_{i=1}^{N}\), buscamos los parámetros \(\boldsymbol{\theta}\) que minimizan:

Función de coste \displaystyle J(\boldsymbol{\theta}) = \frac{1}{N}\sum_{i=1}^{N} \mathcal{L}\bigl(f(\mathbf{x}_i;\boldsymbol{\theta}),\; y_i\bigr)

donde \(f(\mathbf{x}; \boldsymbol{\theta})\) es la predicción del modelo (por ejemplo, un MLP), \(\mathcal{L}\) es la función de pérdida por muestra (MSE, cross-entropy, etc.) y \(\boldsymbol{\theta}\) agrupa todos los pesos y biases de la red.

🔑

Idea fundamental: Una red neuronal moderna puede tener millones (o miles de millones) de parámetros. No podemos resolver \(\nabla J = 0\) analíticamente. Necesitamos un método iterativo: el descenso del gradiente.

¿Por qué no resolver analíticamente?

En regresión lineal, minimizar el MSE tiene una solución cerrada (la ecuación normal). Pero en redes neuronales, la composición de funciones no lineales crea un paisaje de pérdida (loss landscape) con:

  • No convexidad: múltiples mínimos locales y puntos de silla.
  • Alta dimensionalidad: el espacio de parámetros tiene millones de dimensiones.
  • Interdependencia: cada parámetro afecta a la pérdida a través de múltiples caminos.

🧪 Paisaje de pérdida de una red neuronal

Visualización simplificada en 2D. Observa los mínimos locales, puntos de silla y la complejidad del terreno que debe navegar el optimizador. Haz click para colocar un punto de inicio.

0.050
Iteración: 0 · Pérdida:

⛰️ Descenso del gradiente

El descenso del gradiente (Gradient Descent, GD) es el algoritmo que permite navegar el paisaje de pérdida hacia un mínimo. La idea es sencilla: en cada paso, calculamos la dirección de máximo crecimiento de la función (el gradiente) y nos movemos en la dirección opuesta.

Intuición: la analogía del montañero

Imagina que estás en la cima de una montaña con los ojos vendados y quieres llegar al valle. ¿Qué haces? En cada paso, palpas el suelo alrededor para detectar la pendiente más pronunciada y das un paso colina abajo. Eso es exactamente lo que hace el descenso del gradiente.

La regla de actualización

En cada iteración \(t\), actualizamos todos los parámetros simultáneamente:

Actualización GD \displaystyle \boldsymbol{\theta}_{t+1} = \boldsymbol{\theta}_t - \eta \cdot \nabla_{\boldsymbol{\theta}} J(\boldsymbol{\theta}_t)

donde:

  • \(\boldsymbol{\theta}_t\): vector de parámetros en la iteración \(t\).
  • \(\eta\) (learning rate): tasa de aprendizaje, un escalar positivo que controla el tamaño del paso.
  • \(\nabla_{\boldsymbol{\theta}} J\): el gradiente de la función de coste respecto a todos los parámetros.
💡

El signo negativo es crucial: el gradiente apunta en la dirección de máximo crecimiento, así que nos movemos en la dirección opuesta (máximo decrecimiento) para minimizar la pérdida.

Gradient Descent por lotes (Batch GD)

La versión original del algoritmo calcula el gradiente usando todo el dataset en cada iteración:

Batch GD \displaystyle \nabla_{\boldsymbol{\theta}} J(\boldsymbol{\theta}) = \frac{1}{N}\sum_{i=1}^{N} \nabla_{\boldsymbol{\theta}} \mathcal{L}\bigl(f(\mathbf{x}_i;\boldsymbol{\theta}),\; y_i\bigr)

Vamos a desgranar esta fórmula. Lo que dice es: para saber en qué dirección ajustar los parámetros \(\boldsymbol{\theta}\), pasamos cada una de las \(N\) muestras del dataset por la red, calculamos cuánto contribuye cada muestra al error (el gradiente individual \(\nabla_{\boldsymbol{\theta}} \mathcal{L}_i\)), y promediamos todos esos gradientes. El resultado es un vector que apunta en la dirección media de máximo crecimiento de la pérdida. Al movernos en la dirección opuesta (con el signo menos de la regla de actualización), reducimos la pérdida promedio sobre todo el dataset.

Esta media tiene una propiedad importante: es el gradiente exacto de la función de coste \(J\), sin ninguna aproximación. Cada paso va en la dirección óptima para reducir la pérdida total. Sin embargo, el precio es alto: si tu dataset tiene 1 millón de muestras, cada único paso de actualización requiere hacer 1 millón de forward passes y 1 millón de backward passes. En datasets modernos de imágenes, texto o audio, esto hace que el Batch GD puro sea prohibitivamente lento y, en muchos casos, ni siquiera cabe en la memoria de la GPU. Aquí es donde entran las variantes estocásticas que veremos en la siguiente sección.

Ventajas:

  • Gradiente exacto → convergencia estable y predecible.
  • Usa toda la información disponible en cada paso.

Desventajas:

  • Muy costoso: con millones de muestras, un solo paso requiere evaluar toda la red N veces.
  • No cabe en memoria si el dataset es muy grande.
  • Puede quedar atrapado en mínimos locales poco profundos (sin ruido que le ayude a escapar).
🧪 Prueba el descenso del gradiente interactivo →

🎲 SGD y Mini-Batches

La solución al coste computacional de Batch GD es no usar todo el dataset en cada paso. En lugar de eso, estimamos el gradiente con un subconjunto aleatorio de muestras. Esto nos da tres variantes:

Stochastic Gradient Descent (SGD)

En SGD puro, calculamos el gradiente con una sola muestra aleatoria en cada iteración:

SGD puro \displaystyle \boldsymbol{\theta}_{t+1} = \boldsymbol{\theta}_t - \eta \cdot \nabla_{\boldsymbol{\theta}} \mathcal{L}\bigl(f(\mathbf{x}_i;\boldsymbol{\theta}_t),\; y_i\bigr)

donde \(i\) se elige aleatoriamente del dataset en cada paso. La ventaja es que cada actualización es extremadamente barata (una sola muestra); la desventaja es que el gradiente de una sola muestra puede ser una estimación muy ruidosa del gradiente real, haciendo que la trayectoria de optimización sea errática.

Mini-Batch Gradient Descent

En la práctica, usamos mini-batches: subconjuntos de tamaño \(B\) (típicamente 32, 64, 128 o 256 muestras):

Mini-batch GD \displaystyle \boldsymbol{\theta}_{t+1} = \boldsymbol{\theta}_t - \eta \cdot \frac{1}{B}\sum_{j=1}^{B} \nabla_{\boldsymbol{\theta}} \mathcal{L}\bigl(f(\mathbf{x}_{i_j};\boldsymbol{\theta}_t),\; y_{i_j}\bigr)

El mini-batch es el punto dulce entre ambos extremos. Con \(B = 32\) o \(B = 64\), el gradiente estimado es suficientemente representativo del gradiente real (la varianza se reduce como \(1/\sqrt{B}\)), y además las operaciones se vectorizan eficientemente en GPU gracias al paralelismo sobre tensores. Un mini-batch de 32 muestras no tarda 32× más que una sola: las multiplicaciones matriciales en batch son casi tan rápidas como una individual, gracias a la arquitectura SIMT de las GPUs.

🔑

En la práctica: cuando la gente dice «SGD» en deep learning, casi siempre se refiere a mini-batch gradient descent. El SGD puro (muestra a muestra) casi nunca se usa. Además, los optimizadores modernos como Adam, AdamW o SGD con momentum se basan en mini-batch SGD pero añaden acumulación de momentos y adaptación de la tasa por parámetro.

Comparativa de las tres variantes

Variante Tamaño del lote Ruido Velocidad Uso de memoria
Batch GD \(N\) (todo) Ninguno Lento Muy alto
SGD puro 1 Muy alto Rápido por paso Mínimo
Mini-batch GD \(B\) (32-256) Moderado Rápido Moderado

🧪 Efecto del tamaño del batch en la trayectoria

Observa cómo el tamaño del batch afecta a la trayectoria de optimización. Batch grande = camino suave; batch pequeño = más ruido pero puede escapar de mínimos locales.

32
Paso: 0 · Pérdida: · Ruido σ:

⚙️ Tasa de aprendizaje y tamaño del batch

Tasa de aprendizaje (η)

La tasa de aprendizaje es probablemente el hiperparámetro más importante en el entrenamiento de redes neuronales. Controla cuánto cambian los pesos en cada paso. Encontrar un buen valor no es trivial y se aborda con técnicas de búsqueda de hiperparámetros o con schedulers que ajustan \(\eta\) dinámicamente durante el entrenamiento.

  • η demasiado grande: los pasos son enormes, la pérdida oscila o diverge. El modelo "salta" por encima de los mínimos.
  • η demasiado pequeño: la convergencia es extremadamente lenta. El modelo puede quedar atrapado en mínimos locales poco profundos.
  • η adecuado: convergencia rápida y estable hacia un buen mínimo.
Rango típico \displaystyle \eta \in [10^{-4},\; 10^{-1}] \quad \text{(valores típicos: } 0.001, 0.01, 0.1\text{)}

🧪 Efecto de la tasa de aprendizaje

Compara el descenso con tres tasas de aprendizaje diferentes sobre la misma función.

η = 0.5 (grande) η = 0.05 (adecuado) η = 0.005 (pequeño)

Tamaño del batch (B)

El tamaño del batch tiene efectos profundos en el entrenamiento:

Batch grandeBatch pequeño
Gradiente más preciso Gradiente más ruidoso (actúa como regularización)
Mejor uso del paralelismo de la GPU Menos memoria requerida
Tiende a converger a mínimos más agudos (peor generalización) Tiende a encontrar mínimos más planos (mejor generalización)
Menos actualizaciones por epoch Más actualizaciones por epoch
⚠️

Regla práctica: Si aumentas el batch, aumenta proporcionalmente la tasa de aprendizaje. Esta linear scaling rule (Goyal et al., 2017) mantiene la varianza del gradiente constante y se usa rutinariamente en el entrenamiento distribuido de modelos grandes.

🔄 Epochs, iteraciones y el bucle de entrenamiento

Definiciones clave

  • Iteración (step): una actualización de los pesos usando un mini-batch.
  • Epoch: una pasada completa por todo el dataset de entrenamiento.
  • Iteraciones por epoch: \(\lceil N / B \rceil\), donde \(N\) = muestras y \(B\) = batch size.
Relación \displaystyle \text{iteraciones por epoch} = \left\lceil \frac{N}{B} \right\rceil

Ejemplo: Con un dataset de 50,000 muestras y un batch de 64, cada epoch tiene \(\lceil 50000/64 \rceil = 782\) iteraciones. Si entrenamos 100 epochs, el modelo verá cada muestra ~100 veces y realizará 78,200 actualizaciones de pesos.

El bucle de entrenamiento

Este es el flujo que sigue cualquier entrenamiento de red neuronal. Fíjate en que hay dos bucles anidados: un bucle externo de epochs (pasadas completas por el dataset) y un bucle interno de batches (subconjuntos de datos). En cada iteración del bucle interno se ejecuta un ciclo completo de forward → loss → backward → actualización. Al agotar todos los batches, se completa un epoch.

🔄 El ciclo de entrenamiento animado

Pulsa ▶ para ver la animación del bucle de entrenamiento. Observa cómo se recorren los batches dentro de cada epoch y el ciclo forward → loss → backward → update se repite.

Epoch: · Batch: · Paso:

Inicializar los parámetros \(\boldsymbol{\theta}_0\) aleatoriamente (Xavier, He, etc.).

Para cada epoch \(e = 1, 2, \ldots, E\):

• Mezclar (shuffle) el dataset aleatoriamente.

• Dividir en \(\lceil N/B \rceil\) mini-batches de tamaño \(B\).

Para cada mini-batch \(\mathcal{B}\) (se repite \(\lceil N/B \rceil\) veces por epoch):

a) Forward pass: calcular \(\hat{y}_i = f(\mathbf{x}_i; \boldsymbol{\theta})\) para cada muestra del batch.

b) Calcular la pérdida: \(J = \frac{1}{B}\sum_{i \in \mathcal{B}} \mathcal{L}(\hat{y}_i, y_i)\)

c) Backward pass: calcular \(\nabla_{\boldsymbol{\theta}} J\) mediante backpropagation.

d) Actualizar: \(\boldsymbol{\theta} \leftarrow \boldsymbol{\theta} - \eta \cdot \nabla_{\boldsymbol{\theta}} J\)

Evaluar en el conjunto de validación al final de cada epoch. Si la pérdida de validación deja de mejorar, detener el entrenamiento (early stopping, una técnica de regularización que se explica en profundidad en el módulo de Técnicas de Entrenamiento → Regularización).

🧪 Visualización del bucle de entrenamiento

Observa cómo la pérdida disminuye a lo largo de los epochs. La curva de entrenamiento (verde) y la de validación (naranja) deben converger sin que la brecha se abra (sobreajuste).

50
Train loss Val loss

➡️ Forward pass (propagación directa)

El forward pass es el proceso de calcular la salida de la red dados unos datos de entrada. Los datos fluyen capa por capa, desde la entrada hasta la salida, aplicando en cada capa una transformación lineal seguida de una no linealidad.

Para cada capa \(l = 1, 2, \ldots, L\)

Forward pass \displaystyle \mathbf{z}^{(l)} = \mathbf{W}^{(l)}\mathbf{a}^{(l-1)} + \mathbf{b}^{(l)}, \quad \mathbf{a}^{(l)} = \sigma^{(l)}(\mathbf{z}^{(l)})

donde:

  • \(\mathbf{a}^{(0)} = \mathbf{x}\): la entrada a la red.
  • \(\mathbf{z}^{(l)}\): la pre-activación (salida lineal) de la capa \(l\).
  • \(\mathbf{a}^{(l)}\): la activación (salida no lineal) de la capa \(l\).
  • \(\mathbf{W}^{(l)}\): la matriz de pesos de la capa \(l\).
  • \(\mathbf{b}^{(l)}\): el vector de biases de la capa \(l\).
  • \(\sigma^{(l)}\): la función de activación (ReLU, sigmoid, etc.).

La predicción final es \(\hat{\mathbf{y}} = \mathbf{a}^{(L)}\). Es crucial guardar todos los valores intermedios (\(\mathbf{z}^{(l)}, \mathbf{a}^{(l)}\)) porque los necesitaremos para el backward pass. Esto explica por qué el entrenamiento consume más memoria que la inferencia: durante el forward pass en entrenamiento, se almacena un grafo computacional completo con todas las activaciones intermedias. En inferencia, cada capa puede descartar su entrada una vez calculada la salida, pero en entrenamiento no, porque la regla de la cadena necesita acceder a esos valores para calcular los gradientes.

🧪 Forward pass animado

Observa cómo los datos fluyen capa a capa a través de la red. Cada neurona aplica la multiplicación de pesos, suma el bias y pasa por la activación.

Nota sobre eficiencia: En la práctica, el forward pass procesa un mini-batch completo de forma matricial (no muestra por muestra), aprovechando las operaciones sobre tensores. PyTorch y TensorFlow optimizan estas operaciones usando BLAS/cuBLAS en GPU, alcanzando TFLOPs de rendimiento.

⬅️ Backpropagation: la regla de la cadena en acción

El backpropagation (retropropagación, abreviado backprop) es el algoritmo que calcula eficientemente los gradientes de la función de pérdida respecto a cada parámetro de la red. Fue popularizado por Rumelhart, Hinton y Williams en 1986 y es el motor fundamental del deep learning.

🔑

Backpropagation no es un optimizador. Es un algoritmo para calcular gradientes. El optimizador (SGD, Adam, etc.) es el que usa esos gradientes para actualizar los pesos.

La regla de la cadena

El corazón del backpropagation es la regla de la cadena del cálculo diferencial. Si tenemos funciones compuestas \(y = f(g(x))\), la derivada es:

Regla de la cadena \displaystyle \frac{dy}{dx} = \frac{dy}{dg} \cdot \frac{dg}{dx}

En una red neuronal, la salida es una composición de muchas funciones:

Composición \displaystyle \hat{y} = \sigma^{(L)}\Bigl(\mathbf{W}^{(L)} \cdot \sigma^{(L-1)}\bigl(\mathbf{W}^{(L-1)} \cdots \sigma^{(1)}(\mathbf{W}^{(1)}\mathbf{x} + \mathbf{b}^{(1)}) \cdots + \mathbf{b}^{(L-1)}\bigr) + \mathbf{b}^{(L)}\Bigr)

Aplicar la regla de la cadena a esta composición de forma eficiente — sin recalcular gradientes que ya hemos computado — es exactamente lo que hace backpropagation.

El error de retropropagación (δ)

Definimos el error de retropropagación de la neurona \(i\) en la capa \(l\) como:

Delta \displaystyle \delta^{(l)}_i = \frac{\partial J}{\partial z^{(l)}_i}

Es decir, cuánto cambia la pérdida total cuando cambia la pre-activación de esa neurona.

Paso 1: δ de la capa de salida

Para la última capa (\(l = L\)):

Delta salida \displaystyle \boldsymbol{\delta}^{(L)} = \frac{\partial J}{\partial \mathbf{a}^{(L)}} \odot \sigma'^{(L)}(\mathbf{z}^{(L)})

donde \(\odot\) es el producto elemento a elemento (Hadamard) y \(\sigma'\) es la derivada de la función de activación.

Paso 2: Retropropagar δ capa por capa

Para cada capa oculta \(l = L-1, L-2, \ldots, 1\):

Retropropagar δ \displaystyle \boldsymbol{\delta}^{(l)} = \bigl({\mathbf{W}^{(l+1)}}^\top \boldsymbol{\delta}^{(l+1)}\bigr) \odot \sigma'^{(l)}(\mathbf{z}^{(l)})
💡

Observa la elegancia: para calcular \(\delta^{(l)}\), solo necesitamos \(\delta^{(l+1)}\) (que ya calculamos) y los pesos de la capa siguiente \(\mathbf{W}^{(l+1)}\). El gradiente «fluye hacia atrás» por los mismos pesos que se usaron en el forward pass, pero transpuestos.

Esta propagación multiplicativa tiene un efecto colateral: si los pesos o las derivadas de la activación son sistemáticamente menores (o mayores) que 1, los gradientes se reducen (o amplifican) exponencialmente al retroceder por muchas capas. Este es el problema del vanishing/exploding gradient, que se trata en profundidad en Estabilidad del entrenamiento.

Paso 3: Calcular los gradientes de los parámetros

Una vez tenemos todos los \(\delta^{(l)}\), los gradientes de pesos y biases son:

Gradientes \displaystyle \frac{\partial J}{\partial \mathbf{W}^{(l)}} = \boldsymbol{\delta}^{(l)} {\mathbf{a}^{(l-1)}}^\top, \qquad \frac{\partial J}{\partial \mathbf{b}^{(l)}} = \boldsymbol{\delta}^{(l)}

Es decir: el gradiente de cada peso \(W^{(l)}_{ij}\) es simplemente el error retropropagado \(\delta^{(l)}_i\) multiplicado por la activación de la neurona que lo alimenta \(a^{(l-1)}_j\). Elegante y eficiente.

🧪 Prueba la retropropagación interactiva →

📐 Cálculo de gradientes capa por capa

Vamos a aplicar todo lo anterior a un ejemplo concreto: una red con 2 entradas, una capa oculta de 2 neuronas (ReLU) y 1 salida (sigmoide), usando binary cross-entropy.

Arquitectura: 2 → 2 → 1

Red 2→2→1 con pesos etiquetados. Los valores numéricos se usan en el ejemplo de abajo.

Ejemplo numérico completo

Supongamos estos valores iniciales (simplificados):

ParámetroValor
Entrada \(\mathbf{x}\)[0.5, 0.8]
Etiqueta \(y\)1
\(\mathbf{W}^{(1)}\)[[0.4, 0.3], [0.2, 0.6]]
\(\mathbf{b}^{(1)}\)[0.1, 0.1]
\(\mathbf{W}^{(2)}\)[[0.5, 0.7]]
\(\mathbf{b}^{(2)}\)[0.2]

Capa 1 (oculta, ReLU):

\(z^{(1)}_1 = 0.4 \times 0.5 + 0.3 \times 0.8 + 0.1 = 0.54\)

\(z^{(1)}_2 = 0.2 \times 0.5 + 0.6 \times 0.8 + 0.1 = 0.68\)

\(a^{(1)}_1 = \text{ReLU}(0.54) = 0.54\)

\(a^{(1)}_2 = \text{ReLU}(0.68) = 0.68\)

Capa 2 (salida, sigmoid):

\(z^{(2)}_1 = 0.5 \times 0.54 + 0.7 \times 0.68 + 0.2 = 0.946\)

\(\hat{y} = a^{(2)}_1 = \sigma(0.946) = 0.7203\)

Pérdida (BCE):

\(J = -[1 \cdot \ln(0.7203) + 0 \cdot \ln(1-0.7203)] = 0.3279\)

Delta de la capa de salida:

\(\frac{\partial J}{\partial a^{(2)}} = \frac{a^{(2)} - y}{a^{(2)}(1-a^{(2)})} = \frac{0.7203 - 1}{0.7203 \times 0.2797} = -1.389\)

\(\sigma'(z^{(2)}) = 0.7203 \times (1 - 0.7203) = 0.2015\)

\(\delta^{(2)} = -1.389 \times 0.2015 = -0.2797\)

Con BCE+sigmoid, esto se simplifica a: \(\delta^{(2)} = \hat{y} - y = 0.7203 - 1 = -0.2797\)

Gradientes de W⁽²⁾ y b⁽²⁾:

\(\frac{\partial J}{\partial W^{(2)}_{11}} = \delta^{(2)} \cdot a^{(1)}_1 = -0.2797 \times 0.54 = -0.1511\)

\(\frac{\partial J}{\partial W^{(2)}_{12}} = \delta^{(2)} \cdot a^{(1)}_2 = -0.2797 \times 0.68 = -0.1902\)

\(\frac{\partial J}{\partial b^{(2)}} = \delta^{(2)} = -0.2797\)

Retropropagar delta a la capa oculta:

\(\delta^{(1)}_1 = W^{(2)}_{11} \cdot \delta^{(2)} \cdot \text{ReLU}'(z^{(1)}_1) = 0.5 \times (-0.2797) \times 1 = -0.1399\)

\(\delta^{(1)}_2 = W^{(2)}_{12} \cdot \delta^{(2)} \cdot \text{ReLU}'(z^{(1)}_2) = 0.7 \times (-0.2797) \times 1 = -0.1958\)

Gradientes de W⁽¹⁾ y b⁽¹⁾:

\(\frac{\partial J}{\partial W^{(1)}_{11}} = \delta^{(1)}_1 \cdot x_1 = -0.1399 \times 0.5 = -0.0699\)

\(\frac{\partial J}{\partial W^{(1)}_{12}} = \delta^{(1)}_1 \cdot x_2 = -0.1399 \times 0.8 = -0.1119\)

\(\frac{\partial J}{\partial W^{(1)}_{21}} = \delta^{(1)}_2 \cdot x_1 = -0.1958 \times 0.5 = -0.0979\)

\(\frac{\partial J}{\partial W^{(1)}_{22}} = \delta^{(1)}_2 \cdot x_2 = -0.1958 \times 0.8 = -0.1566\)

Actualización con η = 0.1:

\(W^{(2)}_{11} = 0.5 - 0.1 \times (-0.1511) = 0.5151\)

\(W^{(2)}_{12} = 0.7 - 0.1 \times (-0.1902) = 0.7190\)

Tras esta actualización, la pérdida sería menor que los 0.3279 iniciales. Repitiendo este proceso miles de veces, la red converge a un mínimo de la función de pérdida.

Complejidad computacional

Una propiedad notable del backpropagation es su eficiencia:

  • El forward pass tiene coste \(\mathcal{O}(\text{parámetros})\).
  • El backward pass tiene el mismo orden de complejidad que el forward pass.
  • Calcular todos los gradientes cuesta ≈2× el coste de una predicción.

Sin backpropagation, calcular el gradiente de cada peso requeriría una perturbación individual: \(\mathcal{O}(\text{parámetros}^2)\). Para una red con 1M de parámetros, backprop es un millón de veces más eficiente.

El ciclo completo de entrenamiento

Ahora que entendemos la complejidad de cada paso (forward + backward ≈ 2× forward), podemos calcular el coste total del entrenamiento. Recordemos que el dataset se divide en mini-batches de tamaño \(B\), cada uno de los cuales produce una actualización de pesos. El número total de actualizaciones (pasos de backpropagation) en todo el entrenamiento es:

Pasos totales \displaystyle \text{pasos totales} = E \times \left\lceil \frac{N}{B} \right\rceil

donde \(E\) es el número de epochs, \(N\) es el tamaño del dataset y \(B\) es el tamaño del batch. Este número puede ser sorprendentemente grande: un modelo entrenado en ImageNet (1.28M imágenes) con batch 256 durante 90 epochs realiza \(90 \times 5000 = 450{,}000\) pasos de backpropagation. Para un LLM como LLaMA-2 entrenado con 2 billones de tokens, la cifra se dispara a millones de pasos.

Es importante entender esta relación porque las decisiones de diseño están conectadas: un batch más grande reduce el número de pasos por epoch (y por tanto el tiempo por epoch), pero puede requerir más epochs para converger y necesita más memoria GPU. Un batch más pequeño da más pasos (más actualizaciones), lo que en principio permite una convergencia más rápida en epochs, pero cada paso es más ruidoso.

🧪 Calculadora de pasos de entrenamiento

Ajusta el tamaño del dataset, el tamaño del batch y el número de epochs para ver cuántos pasos de backpropagation realizará tu entrenamiento y cómo se distribuyen los batches dentro de cada epoch.

10,000
64
50
Vista de 1 epoch: cada bloque = 1 batch (1 paso de backprop)
🧪 Herramientas interactivas
🏭 Casos de uso