El modelo que se empleó en la clase es una red neuronal que tiene dos entradas, dos neuronas ocultas y una neurona de salida. La función de activación utilizada es la sigmoide. La finalidad de este código es llevar a cabo n iteraciones del proceso de retropropagación, que tiene como objetivo el entrenamiento del algoritmo mediante la optimización de los pesos. Así, la red neuronal será capaz de aprender a asociar entradas arbitrarias con su salida correspondiente.
Primero se asignan los pesos iniciales de cada aristas y los sesgos para cada entrada. En este caso se organizaron dentro de una matriz donde cada fila representa una entrada distinta.
#Pesos de las aristas
M_pesos <- matrix(c(0.1,0.5,-0.7,0.3,0.2,0.4,
0.1,0.5,-0.7,0.3,0.2,0.4,
0.1,0.5,-0.7,0.3,0.2,0.4,
0.1,0.5,-0.7,0.3,0.2,0.4),
ncol = 6, byrow = TRUE)
#Valor de los sesgos
b1 <- 0
b2 <- 0
b3 <- 0
#Función de activación Sigmoide
funcion_activacion <- function(x) {
1/(1 + exp(-x))
}
#Derivada de la función de activación
deriv_activacion <- Deriv(funcion_activacion, "x" )
#Función que ejecuta una época
funcion_epoca <- function(x1,x2,i) {
z1 = M_pesos[i,1]*x1 + M_pesos[i,3]*x2 + b1
h1 = funcion_activacion(z1)
z2 = M_pesos[i,2]*x1 + M_pesos[i,4]*x2 + b2
h2 = funcion_activacion(z2)
z3 = M_pesos[i,5]*h1 + M_pesos[i,6]*h2 + b3
o1 = funcion_activacion(z3)
return(list(z1=z1, h1=h1, z2=z2, h2=h2, z3=z3, o1=o1))
}
#Función error total
funcion_error_total <- function(o_esp, o1) {
0.5 * (o_esp-o1)^2
}
#Derivada del error total
deriv_error_total <- Deriv(funcion_error_total, "o1")
#Función que genera al grafo
funcion_grafico <- function(x1,x2,x3,x4,x5,x6,salida, entrada1, entrada2){
#Nodos
nodes <- data.frame(
name = c("X1","X2","H1","H2","O1","B1","B2"),
label = c(paste("X1\n",entrada1),paste("X1\n",entrada2),"H1","H2",paste("O1\n",salida),"B1","B2"),
type = c("input","input","hidden","hidden","output","bias","bias"),
x = c(0,0,3.5,3.5,7,2,5),
y = c(3,0,3,0,1.5,4,4)
)
#Aristas
edges <- data.frame(
from = c("X1","X1","X2","X2","H1","H2","B1","B1","B2"),
to = c("H1","H2","H1","H2","O1","O1","H1","H2","O1"),
label= c(paste("W1 = ",x1),paste("W2 = ",x2),paste("W3 = ",x3)
,paste("W4 = ",x4),paste("W5 = ",x5),paste("W6 = ",x6),
"B1 = 0","B2 = 0","B3 = 0"),
color= c("black","black","black","black","black","black","#1874CD","#1874CD","#1874CD")
)
#Creación del grafo
g <- graph_from_data_frame(edges, vertices = nodes)
ggraph(g, layout = "manual", x = nodes$x, y = nodes$y) +
#Aristas
geom_edge_link(aes(label = label, color = I(color)),
angle_calc = 'along',
label_dodge = unit(2.5, 'mm'),
label_size = 3,
label_pos = 0.3,
arrow = arrow(length = unit(3, 'mm'), type = "closed"),
end_cap = circle(16, 'pt'))+
#Nodos
geom_node_point(aes(shape = type, color = type, fill = type), size = 15, stroke = 1) +
geom_node_text(aes(label = label, x = x, y = y), color="black", size=4, fontface="bold") +
scale_shape_manual(values = c(
input = 21, hidden = 21, output = 21, bias = 17 #21 es circulo, 17 es triangulo
)) +
scale_fill_manual(values=c("input"="#00CDCD","hidden"="#00CDCD","output"="#00CDCD","bias"="black")) +
scale_color_manual(values = c(
input = "black", hidden = "black", output = "black", bias = "grey"
)) +
guides(shape = "none", color = "none", fill = "none")+
theme_void()
}
Al ejecutar el código, se define una matriz de 4x3, donde cada fila corresponde a una entrada. Las dos primeras columnas representan las variables de entrada x1 y x2, mientras que la tercera columna contiene el valor esperado asociado a cada caso. Además, se especifica el número de épocas que se desean observar.
Posteriormente, el código entra en un ciclo iterativo que recorre cada época. En cada una de ellas, la red neuronal se inicializa con los pesos actuales, se calcula la salida obtenida y se muestra el error total. A continuación, se lleva a cabo internamente el proceso de retropropagación, mediante el cual se ajustan los pesos de la red. Este procedimiento se ejecuta dentro de otro ciclo que controla qué entrada se está procesando en la época correspondiente. De esta manera, en cada época se evalúan todas las entradas y se actualizan los pesos de acuerdo con los resultados obtenidos.
Para ilustrar el proceso, en este ejemplo se realizará una prueba utilizando 5 épocas.
M_ent <- matrix(c(0,0,0,
0,1,1,
1,1,0,
1,0,1),
ncol = 3, byrow = TRUE)
num_epocas <- 5
tasa_de_aprendizaje <- 0.25
#En este ciclo realizamos las operaciones de retropropagación
k <- 1
while(k <= num_epocas){
for (i in 1:4){
print(funcion_grafico(M_pesos[i,1],M_pesos[i,2],M_pesos[i,3],M_pesos[i,4],M_pesos[i,5],M_pesos[i,6], M_ent[i,3],M_ent[i,1],M_ent[i,2]))
#El error y el valor de o1 (la salida)
ep<-funcion_epoca(M_ent[i,1],M_ent[i,2], i)
print(paste("El valor de o1 o salida de la época",k, "en la entrada",i, "es",ep$o1 ))
print(paste("El error total para la red neuronal respecto al valor esperado en la época",k,"en la entrada",i, "es de",funcion_error_total(M_ent[i,3],ep$o1)))
#Retropropagacion
#Capa de salida
deriv_z3 = deriv_error_total(M_ent[i,3], ep$o1)*deriv_activacion(ep$z3)
deriv_w5 = deriv_z3*ep$h1
deriv_w6 = deriv_z3*ep$h2
act5 = M_pesos[i,5] - tasa_de_aprendizaje*deriv_w5
act6 = M_pesos[i,6] - tasa_de_aprendizaje*deriv_w6
#Capa oculta
deriv_z1 = deriv_z3*M_pesos[i,5]*deriv_activacion(ep$z1)
deriv_z2 = deriv_z3*M_pesos[i,6]*deriv_activacion(ep$z2)
#neurona h1
deriv_w1 = deriv_z1*M_ent[i,1]
deriv_w3 = deriv_z1*M_ent[i,2]
act1 = M_pesos[i,1] - tasa_de_aprendizaje*deriv_w1
act3 = M_pesos[i,3] - tasa_de_aprendizaje*deriv_w3
#neurona h2
deriv_w2 = deriv_z2*M_ent[i,1]
deriv_w4 = deriv_z2*M_ent[i,2]
act2 = M_pesos[i,2] - tasa_de_aprendizaje*deriv_w2
act4 = M_pesos[i,4] -tasa_de_aprendizaje*deriv_w4
#Se reemplazan los pesos
M_pesos[i,1] = act1
M_pesos[i,2] = act2
M_pesos[i,3] = act3
M_pesos[i,4] = act4
M_pesos[i,5] = act5
M_pesos[i,6] = act6
}
k <- k+1
}
## [1] "El valor de o1 o salida de la época 1 en la entrada 1 es 0.574442516811659"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 1 en la entrada 1 es de 0.164992102560457"
## [1] "El valor de o1 o salida de la época 1 en la entrada 2 es 0.573498503710098"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 1 en la entrada 2 es de 0.0909517631687627"
## [1] "El valor de o1 o salida de la época 1 en la entrada 3 es 0.58585557419851"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 1 en la entrada 3 es de 0.171613376909733"
## [1] "El valor de o1 o salida de la época 1 en la entrada 4 es 0.587582280463471"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 1 en la entrada 4 es de 0.0850441876938554"
## [1] "El valor de o1 o salida de la época 2 en la entrada 1 es 0.570145936717972"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 2 en la entrada 1 es de 0.162533194578007"
## [1] "El valor de o1 o salida de la época 2 en la entrada 2 es 0.576379711212853"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 2 en la entrada 2 es de 0.0897270745360528"
## [1] "El valor de o1 o salida de la época 2 en la entrada 3 es 0.580505928782137"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 2 en la entrada 3 es de 0.168493566675606"
## [1] "El valor de o1 o salida de la época 2 en la entrada 4 es 0.591662362884512"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 2 en la entrada 4 es de 0.0833698129425298"
## [1] "El valor de o1 o salida de la época 3 en la entrada 1 es 0.565860140135438"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 3 en la entrada 1 es de 0.160098849097049"
## [1] "El valor de o1 o salida de la época 3 en la entrada 2 es 0.579242611989336"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 3 en la entrada 2 es de 0.0885183897827782"
## [1] "El valor de o1 o salida de la época 3 en la entrada 3 es 0.575205249940286"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 3 en la entrada 3 es de 0.165430539779433"
## [1] "El valor de o1 o salida de la época 3 en la entrada 4 es 0.595689757187464"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 3 en la entrada 4 es de 0.081733386221566"
## [1] "El valor de o1 o salida de la época 4 en la entrada 1 es 0.561586647111575"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 4 en la entrada 1 es de 0.15768978110701"
## [1] "El valor de o1 o salida de la época 4 en la entrada 2 es 0.582087260829031"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 4 en la entrada 2 es de 0.0873255287806913"
## [1] "El valor de o1 o salida de la época 4 en la entrada 3 es 0.569953724963229"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 4 en la entrada 3 es de 0.16242362429973"
## [1] "El valor de o1 o salida de la época 4 en la entrada 4 es 0.599664784644433"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 4 en la entrada 4 es de 0.0801341423268939"
## [1] "El valor de o1 o salida de la época 5 en la entrada 1 es 0.557326941608742"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 5 en la entrada 1 es de 0.155306659921477"
## [1] "El valor de o1 o salida de la época 5 en la entrada 2 es 0.584913705115242"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 5 en la entrada 2 es de 0.0861483161005782"
## [1] "El valor de o1 o salida de la época 5 en la entrada 3 es 0.564751398139485"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 5 en la entrada 3 es de 0.159472070850251"
## [1] "El valor de o1 o salida de la época 5 en la entrada 4 es 0.603587784755437"
## [1] "El error total para la red neuronal respecto al valor esperado en la época 5 en la entrada 4 es de 0.078571322197551"
Como se puede ver, a medida que cada época se lleva a cabo, el valor de salida se aproxima cada vez más al valor esperado (en este caso 1), y el error total disminuye, acercándose a 0. Esto permite determinar la eficacia del algoritmo de aprendizaje.