Las Redes Neuronales son un modelo computacional que simula el comportamiento real de las neuronas dentro de nuestros cerebros. Básicamente son un conjunto de "neuronas" conectadas entre si, que procesan un determinado conjunto de entrada y generan un conjunto de salida.
Para entender mejor este proceso pongamos un ejemplo hipotético:
Un estudio realizado a una población de personas demuestra que el color de los ojos de un individuo depende de:
El estudio resumió que cuando las características del padre son: (color de los ojos: azul, grupo sanguíneo: O+) y las características de la madre son: (color de los ojos: café, grupo sanguíneo: B+) el individuo nace con los ojos verde. Así se definieron 2 reglas más para: los colores de los ojos café y azules. Ahora si existiera un algoritmos que procesara estos datos y fuera capaz de "aprender", podíamos determinar para cualquier pareja, cuyas características oscilen en la media de las estudiadas, el color de los ojos de sus hijos. Básicamente esto es posible mediante las Redes Neuronales Artificiales.
El funcionamiento a escala más básica de una red neuronal se puede describir con la siguiente imagen:
Podemos observar un modelo con un conjunto de entradas (x1, x2 ...)
, un conjunto de selectores (w1, w2, ...)
(u1, u2 ...)
y un conjunto de salida (y1, y2 ...)
. El conjunto de salida depende directamente del valor de cada selector, por lo que podemos deducir que modificando los selectores para una misma entrada podemos obtener diferentes valores de salida. Ahora conociendo que para determinado conjunto de entrada existe un conjunto de salida, el problema seria encontrar la configuración exacta de los selectores que minimice la diferencia entre la salida esperada y la salida real del sistema. En esto consiste lo que se conoce como Entrenamiento de la red o Proceso de Aprendizaje.
Como mencionábamos el objetivo principal es minimizar el error o lo que es lo mismo la diferencia que existe entre la salida que produce la red y la salida esperada. Este error lo podemos minimizar haciendo uso de las derivadas. Para encontrar el valor que minimiza una determinada función se procede igualando la primera derivada a cero, pero no es muy computable el cálculo de derivadas y menos cuando la función depende de más de una variable, todo esto se simplifica utilizando el algoritmo del Deseoso del Gradiente.
El algoritmo lo que nos dice es que el valor que minimiza una función lo determina ir en contra de la primera derivada y esto es lo más lógico ya que la primera derivada nos da la pendiente de la recta tangente a un determinado punto de la curva, e ir en contra de esta pendiente significa descender por la curva. Veamos esto gráficamente:
Veaemos un ejemplo. Suponiendo la función:
$~{\large\textcolor{#00252d}{F(x) = x^2}}$
Para encontrar el mínimo comencemos por un valor de x aleatorio. $~{\large\textcolor{#00252d}{x_0=2}}$
Ahora la regla nos dice que:
$~{\large\textcolor{#00252d}{dx=-F`(x)}}$
y
$~{\large\textcolor{#00252d}{dx=x_1-x_0}}$
por tanto
$~{\large\textcolor{#00252d}{x_1=x_0 - \alpha F`(x_0)}}$
Para un valor de $\alpha = 0.5$ se puede apreciar que el valor mínimo se encuentra en la iteración número 7 con un error de 0.0008.
x | F(x) | F'(x) |
---|---|---|
x0=2 | 4 | 4 |
x1=1,2 | 1.44 | 2.4 |
x2=0.72 | 0.51 | 1.44 |
x3=0.43 | 0.18 | 0.86 |
x4=0.25 | 0.06 | 0.5 |
x5=0.15 | 0.02 | 0.3 |
x6=0.09 | 0.0008 | 0.1 |
Ahora veremos que ocurre dentro de la neurona:
Toda neurona cuenta con un determinado número de entradas (z1, z2, z3)
y cada entrada esta determinada por un valor denominado peso (w1, w2, w3)
. También posee una conexión, propia de cada neurona, a cuyo peso se le denomina umbral de activación (u)
. A la salida de la neurona (a)
se le denomina Activación y esta determinada por una Función de activación.
Existes una gran variedad de funciones de activación como:
En este caso estaremos trabajando con la sigmoidea:
$~{\large\textcolor{#00252d}{F(x)=(1+e^{-x})^{-1}}}$
Y su derivada cumple con la siguiente propiedad:
$~{\large\textcolor{#00252d}{F`(x) = F(x)(1-F(x))}}$
La función de activación recibe como parámetro una suma ponderada determinada por las entradas, los pesos y el umbral:
$~{\large\textcolor{#00252d}{a=F(u + z_1 * w_1 + z_2 * w_2 + z_3 * w_3)}}$
Mientras mayor sean los pesos mayor será la contribución de estos a la activación de la neurona. El umbral determina el comportamiento de la neurona, si el umbral es muy grande en comparación con los pesos, la neurona se excitará al máximo (la salida es el máximo valor que retorna la función de activación) y si el valor del umbral es muy pequeño comparado con los umbrales la neurona se excitará al mínimo (la salida es el mínimo valor que retorna la función de activación).
A continuación les muestro un modelo de una red neuronal:
Toda red neuronal está compuesta por:
Dicho esto veremos la nomenclatura necesaria para poder determinar las ecuaciones que rigen a una Red Neuronal.
Como mencionábamos las conexiones entre neuronas esta determinada por un peso w
. Ahora definiremos como referirnos al peso de cualquier conexión:
$~{ \large\textcolor{#00252d}{W_{i,j}^{k} }}$
Peso que conecta la neurona i
de la capa k
con la neurona j
de la capa k+1
.
$~{ \large\textcolor{#00252d}{i = 1,2,3...n_k}}$ $~{ \large\textcolor{#00252d}{j = 1,2,3...n_{k+1}}}$
Algo similar se hace con los umbrales:
$~{\large\textcolor{#00252d}{u_{i}^{k}}}$
Umbral de la neurona i
de la capa k
.
$~{\large\textcolor{#00252d}{i=1,2,3...n_k}}$
Y para representar la salida de cada neurona:
$~{\large\textcolor{#00252d}{a_{k}^{i}}}$
Salida de la neurona i
de la capa k
.
Ahora generalizando lo que ya vimos de la activación de la neurona:
Para k=1
:
$~{\large\textcolor{#00252d}{a_{k}^{i} = x_i}}$
Para k>1
:
$~{\large\textcolor{#00252d}{a_{i}^{k} = F( u_{i}^{k} + \sum_{j=1}^{n_{k-1}}}a_{j}^{k-1}w_{j,i}^{k-1}) }$
Hasta este momento ya podemos construir una estructura que soporte las operaciones que se suelen realizar en una Red Neuronal y también podemos calcular la salida de la red, pero ... Cómo la red puede aprender?.
Back Propagation es uno de los métodos que posibilita que los pesos y umbrales se modifiquen de manera que se minimiza el error. Su funcionamiento se reduce a propagar el error desde las capas superiores hasta las inferiores, determinando las derivadas parciales de los pesos y los umbrales con respecto al error, y de esta manera poder actualizar sus valores mediante el Descenso del Gradiente que ya mencionamos.
Veamos un ejemplo:
En la siguiente red neuronal se quiere calcular la derivada parcial de $y1$ con respecto al peso $W_{11}^{1}$.
En principio tendríamos que derivar la siguiente función:
$~{\large\textcolor{#00252d}{y_1 = a_1^4}}$
pero
$~{\large\textcolor{#00252d}{a_1^4 = F(u_1^4 + w_{11}^3a_1^3 +w_{21}^3a_2^3)}}$
Y así sucesivamente tendríamos que ir abriendo la expresión hasta que todo quede en función de los pesos y la entrada. Como ves esto supone un trabajo demasiado tedioso y propicio a cometer errores. Afortunadamente existe una regla para obtener estas derivadas y te la muestro a continuación:
$~{\large\textcolor{#00252d}{\frac{\delta y_1}{\delta w_{11}^1} = a_1^4(1-a_1^4)w_{11}^3a_1^3(1-a_1^3)w_{11}^2a_1^2(1-a_1^2)a_1^1 + a_1^4(1-a_1^4)w_{21}^3a_2^3(1-a_2^3)w_{12}^2a_1^2(1-a_1^2)a_1^1}}$
Se puede apreciar el patrón: se multiplica la derivada de la función de activación (evaluada en la salida de cada neurona) por el peso correspondiente de la capa i - 1
, así hasta llegar a la capa de entrada. Note que la variable respecto a la cual se deriva no esta presente en la ecuación ya que su derivada es 1.
Para el caso de los umbrales es algo parecido, solo hay que tener en cuenta que los umbrales no están conectados a ninguna entrada (inicialmente están conectados a un valor de 1).
Veamos un ejemplo:
$~{\large\textcolor{#00252d}{\frac{\delta y_1}{\delta u_{1}^1} = a_1^4(1-a_1^4)w_{11}^3a_1^3(1-a_1^3)w_{11}^2a_1^2(1-a_1^2) + a_1^4(1-a_1^4)w_{21}^3a_2^3(1-a_2^3)w_{12}^2a_1^2(1-a_1^2)}}$
Con esta regla se pueden calcular todas las derivadas parciales de la salida con respecto a los umbrales y los pesos para luego hacer uso del Descenso del Gradiente.
Hemos estado hablando que para que una red neuronal aprenda es fundamental ir minimizando el error que existe entre la salida real con respecto a la salida esperada, pero no hemos dicho nada acerca del cálculo de dicho error. El error puede ser calculado de diferentes maneras, una muy simple y funcional es asumir el error como la distancia entre dos puntos. Esto es posible ya que según el número de salidas que tenga una red neuronal así será el número de dimensiones de la misma. Ejemplo si nuestra red tiene dos salidas quiere decir que la salida tiene dos dimensiones. Veamos la siguiente figura:
Como se puede apreciar en la figura la región subrayada se forma ya que existen dos salidas y1
y y2
y el dominio de cada una es [0, 1]
.
Ahora supongamos que la salida real es (z1, z2)
y la salida esperada es (s1, s2)
, podemos definir el error de la siguiente manera:
$~{\large\textcolor{#00252d}{error = \sqrt{(s_1-z_1)^2+(s_2-z_2)^2}}}$
A esta fórmula se le pueden hacer algunos cambios que faciliten la expresión a la hora de derivar. Si tenemos que determinar el mínimo a una expresión como la de este tipo podemos omitir la raíz ya que la derivada de una raíz da una fracción donde la raíz queda en el denominador y solo tiene sentido igualar a 0 el numerador.
Esto nos quedaría así:
$~{\large\textcolor{#00252d}{error = (s_1-z_1)^2+(s_2-z_2)^2}}$
También pudiéramos multiplicar por una constante y no se alteraría el valor del mínimo:
$~{\large\textcolor{#00252d}{error = \frac{1}{2}(s_1-z_1)^2+ \frac{1}{2}(s_2-z_2)^2}}$
Ahora ya lo tenemos todo planteado, fijémonos que el error depende de z1 y z2
(que son las salidas de nuestra red) y estas a su vez dependen de los pesos y los umbrales, con esto ya podemos determinar las derivadas parciales del error con respecto a los pesos y los umbrales.
Nos queda:
$~{\Huge\textcolor{#00252d}{\frac{\delta error}{\delta \star} = \frac{\delta error}{\delta z_1}\frac{\delta z_1}{\delta \star} + \frac{\delta error}{\delta z_2}\frac{\delta z_2}{\delta \star} }}$
pero
$~{\Huge\textcolor{#00252d}{\frac{\delta error}{\delta z_i} = z_i - s_i }}$
y
$~{\Huge\textcolor{#00252d}{\frac{\delta z_i}{\delta \star}}}$ ya la calculamos anteriormente, donde la "estrella" se sustituye por cada peso y cada umbral.
Con este fundamento matemático ya podemos implementar un Perceptrón Multicapa y entrenarlo, a continuación les muestro un resumen de los pasos a seguir:
1
a la capa n
).Con este artículo te expliqué de manera breve el modelo matemático de una red neuronal en el siguiente artículo te mostraré como se puede implementar esta estructura en un lenguaje de programación. Hasta la próxima...