Construye tu propia red neuronal
Etapa 5 de 6v1 · e3f9bfc4

La época de entrenamiento y retropropagación

Combina el forward pass con sigmoide, la función de costo MSE y la regla de la cadena para calcular gradientes y actualizar parámetros sobre un conjunto de datos.

Constrúyelo en tu lenguaje

El tester trata tu programa como una caja negra: sirve cualquier lenguaje. Estos son los más cómodos para este proyecto.

Fundamentos: La regla de la cadena y la retropropagación sin miedo

La retropropagaciónAlgoritmo para entrenar redes neuronales que calcula los gradientes de la función de costo respecto a cada parámetro utilizando la regla de la cadenaVer documentación oficial (backpropagation) suele presentarse como algo intimidante, pero su núcleo es una idea intuitiva: rastrear la causa de un error hacia atrás.

Imagina una cadena de engranajes: giras una perilla (peso ww), que mueve una rueda (combinación lineal zz), que activa una válvula (sigmoide y^\hat{y}), que finalmente afecta la presión del sistema (pérdida LL). Si la presión final es incorrecta, ¿cuánto debes girar la perilla inicial?

La regla de la cadena del cálculo dice simplemente que multiplicamos las tasas de cambio de cada eslabón de la cadena:

∂L∂wj=∂L∂y^⋅∂y^∂z⋅∂z∂wj \frac{\partial L}{\partial w_j} = \frac{\partial L}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} \cdot \frac{\partial z}{\partial w_j}

Desglosemos cada eslabón con total claridad:

  1. Eslabón 1 (¿Cómo cambia la pérdida respecto a la predicción?): Para la pérdida cuadrática individual L=12(y^−y)2L = \frac{1}{2}(\hat{y} - y)^2, su derivada es sencillamente: ∂L∂y^=y^−y\frac{\partial L}{\partial \hat{y}} = \hat{y} - y
  2. Eslabón 2 (¿Cómo cambia la activación sigmoide respecto a zz?): Una de las propiedades matemáticas más hermosas de la función sigmoide es que su derivada se calcula usando su propio valor de salida: ∂y^∂z=y^⋅(1−y^)\frac{\partial \hat{y}}{\partial z} = \hat{y} \cdot (1 - \hat{y})
  3. Eslabón 3 (¿Cómo cambia la suma lineal respecto al peso wjw_j o al sesgo bb?): Como z=w1x1+⋯+wjxj+bz = w_1 x_1 + \dots + w_j x_j + b: ∂z∂wj=xj,∂z∂b=1\frac{\partial z}{\partial w_j} = x_j, \quad \frac{\partial z}{\partial b} = 1

Al multiplicar los dos primeros eslabones obtenemos el término de error local δ\delta:

δ=(y^−y)⋅y^⋅(1−y^) \delta = (\hat{y} - y) \cdot \hat{y} \cdot (1 - \hat{y})

Y por lo tanto, el gradiente para cada parámetro en una muestra es:

Gradiente de wj=δ⋅xj\text{Gradiente de } w_j = \delta \cdot x_j Gradiente de b=δ⋅1=δ\text{Gradiente de } b = \delta \cdot 1 = \delta

¿Qué es una época (epoch)?

Una época es una pasada completa a través de todos los ejemplos del conjunto de entrenamiento:

  1. Para cada muestra del lote, calculamos la predicción y acumulamos sus gradientes y su pérdida.
  2. Al terminar todas las muestras, calculamos el gradiente promedio dividiendo entre el total de muestras NN.
  3. Actualizamos los pesos y el sesgo usando la regla de gradiente que programaste en la etapa anterior.

Tu objetivo en esta etapa

Cuando la entrada contenga "op": "train-epoch", procesa:

  • learning_rate: tasa de aprendizaje α\alpha
  • weights: lista de pesos actuales [w1,…,wd][w_1, \dots, w_d]
  • bias: sesgo actual bb
  • samples: lista de muestras, cada una con formato {"x": [x_1, ..., x_d], "y": y_target}

Algoritmo del bucle paso a paso

  1. Inicializa total_loss = 0.0, grad_w = [0.0] * d, grad_b = 0.0.
  2. Para cada muestra s en samples:
    • Calcula z=∑j=1d(wj⋅s.xj)+bz = \sum_{j=1}^{d} (w_j \cdot s.x_j) + b.
    • Calcula y^=11+e−z\hat{y} = \frac{1}{1 + e^{-z}}.
    • Suma a total_loss la pérdida individual: 0.5×(y^−s.y)20.5 \times (\hat{y} - s.y)^2.
    • Calcula el delta: δ=(y^−s.y)×y^×(1.0−y^)\delta = (\hat{y} - s.y) \times \hat{y} \times (1.0 - \hat{y}).
    • Para cada peso jj: suma δ×s.xj\delta \times s.x_j en grad_w[j].
    • Suma δ\delta en grad_b.
  3. Calcula el promedio dividiendo entre N=len(samples)N = \text{len}(samples):
    • mean_loss = total_loss / N
    • grad_w_mean[j] = grad_w[j] / N
    • grad_b_mean = grad_b / N
  4. Actualiza los parámetros:
    • wj′=wj−α⋅grad_w_mean[j]w_j' = w_j - \alpha \cdot \text{grad\_w\_mean}[j]
    • b′=b−α⋅grad_b_meanb' = b - \alpha \cdot \text{grad\_b\_mean}

Dirección de implementación

Separa la acumulación de gradientes de la actualización de parámetros. Comprueba los valores intermedios con el ejemplo numérico. Mantén entrenamiento e inferencia como operaciones distintas; escribe tú los bucles y reutiliza las funciones anteriores.

Reglas de validación y salida

  1. Si samples está vacío o la dimensión del vector x de alguna muestra no coincide con weights, emite error en stderr y sal con código 1.
  2. Redondea todos los flotantes a 4 decimales con round_value (los enteros o cero se emiten como enteros, ej. 0).
  3. Emite el JSON con claves ordenadas alfabéticamente ("bias", "loss", "weights"):
    json
    { "bias": 0, "loss": 0.125, "weights": [0.0063, -0.0063] }
    

Aquí la pérdida de entrenamiento es la mitad del MSE de la etapa anterior: 0.5 * mean((prediction - target)^2). El factor 0.5 cancela el factor 2 de la derivada. Mantén toda la precisión durante el cálculo y redondea solo al emitir resultados. En entrenamiento de varias épocas, no reutilices parámetros ya redondeados.

Formato de salida y errores

Los ejemplos multilínea se muestran así para facilitar la lectura. Emite JSON compacto, sin espacios opcionales, con las propiedades en el orden de los ejemplos de salida y un salto de línea final. No escribas logs en stdout. Las pruebas comparan texto exacto. Para entradas inválidas, usa stderr con la palabra error, stdout vacío y código 1. Para entradas válidas, código 0. Usa números JSON enteros cuando el resultado sea entero; en neural-network aplica el redondeo a cuatro decimales indicado en la etapa.