Definición de funciones

sigmoid <- function(z) 1 / (1 + exp(-z))

# Función auxiliar para redondeo
r <- function(x, d=4) format(round(x, d), nsmall = d)

Parámetros iniciales

# Datos
x1 <- 0
x2 <- 1
y  <- 1   # target

# Pesos iniciales
w1 <- 0.1   # x1 -> h1
w2 <- 0.5   # x1 -> h2
w3 <- -0.7  # x2 -> h1
w4 <- 0.3   # x2 -> h2
w5 <- 0.2   # h1 -> o1
w6 <- 0.4   # h2 -> o1

# Biases
b1 <- 0
b2 <- 0
b3 <- 0

alpha  <- 0.25
epochs <- 2

Grafo inicial

grViz("
digraph nn {
  rankdir=LR;

  X1 [label='X1=0', shape=circle, style=filled, fillcolor=lightcoral]
  X2 [label='X2=1', shape=circle, style=filled, fillcolor=lightcoral]

  h1 [label='h1', shape=circle, style=filled, fillcolor=lightblue]
  h2 [label='h2', shape=circle, style=filled, fillcolor=lightblue]

  O1 [label='O1', shape=circle, style=filled, fillcolor='#90EE90']

  # edges con pesos
  X1 -> h1 [label='w1=0.1']
  X1 -> h2 [label='w2=0.5']
  X2 -> h1 [label='w3=-0.7']
  X2 -> h2 [label='w4=0.3']
  h1 -> O1 [label='w5=0.2']
  h2 -> O1 [label='w6=0.4']
}
")

Forward Propagation (Época 1)

z1 <- w1 * x1 + w3 * x2 + b1
f1 <- sigmoid(z1)

z2 <- w2 * x1 + w4 * x2 + b2
f2 <- sigmoid(z2)

z3 <- w5 * f1 + w6 * f2 + b3
f3 <- sigmoid(z3)

Etotal <- 0.5 * (y - f3)^2

cat('Forward:\n')
## Forward:
cat(' z1 =', r(z1), ' f1 =', r(f1), '\n')
##  z1 = -0.7000  f1 = 0.3318
cat(' z2 =', r(z2), ' f2 =', r(f2), '\n')
##  z2 = 0.3000  f2 = 0.5744
cat(' z3 =', r(z3), ' f3 =', r(f3), '\n')
##  z3 = 0.2961  f3 = 0.5735
cat(' Etotal =', r(Etotal), '\n')
##  Etotal = 0.0910

Grafo con activaciones

grViz(paste0("
digraph nn {
  rankdir=LR;
  X1 [label='X1=",x1,"', shape=circle, style=filled, fillcolor=lightcoral]
  X2 [label='X2=",x2,"', shape=circle, style=filled, fillcolor=lightcoral]

  h1 [label='h1\\n f1=", r(f1), "', shape=circle, style=filled, fillcolor=lightblue]
  h2 [label='h2\\n f2=", r(f2), "', shape=circle, style=filled, fillcolor=lightblue]

  O1 [label='O1\\n f3=", r(f3), "', shape=circle, style=filled, fillcolor='#90EE90']

  X1 -> h1 [label='w1=", w1, "']
  X1 -> h2 [label='w2=", w2, "']
  X2 -> h1 [label='w3=", w3, "']
  X2 -> h2 [label='w4=", w4, "']
  h1 -> O1 [label='w5=", w5, "']
  h2 -> O1 [label='w6=", w6, "']
}
"))

Backpropagation (una iteración)

delta3 <- (y - f3) * (f3 * (1 - f3))
dE_w5 <- delta3 * f1
dE_w6 <- delta3 * f2

w5_old <- w5
w6_old <- w6

w5 <- w5 - alpha * dE_w5
w6 <- w6 - alpha * dE_w6

dE_z1 <- delta3 * w5_old * (f1 * (1 - f1))
dE_w1 <- dE_z1 * x1
dE_w3 <- dE_z1 * x2

dE_z2 <- delta3 * w6_old * (f2 * (1 - f2))
dE_w2 <- dE_z2 * x1
dE_w4 <- dE_z2 * x2

w1 <- w1 - alpha * dE_w1
w3 <- w3 - alpha * dE_w3
w2 <- w2 - alpha * dE_w2
w4 <- w4 - alpha * dE_w4

cat('Pesos actualizados:\n')
## Pesos actualizados:
cat(' w1 =', r(w1), ' w2 =', r(w2), ' w3 =', r(w3), ' w4 =', r(w4), '\n')
##  w1 = 0.1000  w2 = 0.5000  w3 = -0.7012  w4 = 0.2974
cat(' w5 =', r(w5), ' w6 =', r(w6), '\n')
##  w5 = 0.1913  w6 = 0.3850

Grafo con pesos actualizados

grViz(paste0("
digraph nn {
  rankdir=LR;
  X1 [label='X1=",x1,"', shape=circle, style=filled, fillcolor=lightcoral]
  X2 [label='X2=",x2,"', shape=circle, style=filled, fillcolor=lightcoral]

  h1 [label='h1', shape=circle, style=filled, fillcolor=lightblue]
  h2 [label='h2', shape=circle, style=filled, fillcolor=lightblue]

  O1 [label='O1\\n f3=", r(f3), "', 
    shape=circle, style=filled, fillcolor='#90EE90']


  X1 -> h1 [label='w1=", r(w1), "']
  X1 -> h2 [label='w2=", r(w2), "']
  X2 -> h1 [label='w3=", r(w3), "']
  X2 -> h2 [label='w4=", r(w4), "']
  h1 -> O1 [label='w5=", r(w5), "']
  h2 -> O1 [label='w6=", r(w6), "']
}
"))