El objetivo de este articulo es explicar lo que hay detrás de una red neuronal artificial, esas cajas negras en las que la mayoría de veces simplemente creamos las estructura, introducimos un valor de entrada y por arte de magia obtenemos una predicción de un valor que será mas o menos cercano a la realidad.

Pero detrás de esa magia hay una serie de operaciones matemáticas que siguen una lógica muy estructurada y que en las próximas lineas voy a explicar de una manera practica usando, por supuesto las matemáticas y el lenguaje de programación Python, donde crearemos una red neuronal propia que sea capaz de aprender un sistema de clasificación

¿Que es una red neuronal?

  • Una red neuronal se define como un sistema que consiste en una serie de elementos todos interconectados, llamados «neuronas», que se organizan en capas que procesan la información utilizando respuestas de estado dinámico a entradas externas.
  • En el contexto de esta estructura, la capa de entrada introduce patrones en la red neuronal que tiene una neurona para cada componente presente en los datos de entrada y se comunica a una o más capas ocultas, se considera capas ocultas a todas las capas de la red exceptuando la de entrada y salida. Es en las capas ocultas donde sucede todo el procesamiento, a través de un sistema de conexiones caracterizado por pesos y sesgos (comúnmente conocidos como W yb)

¿Como funciona?

  • Con el valor de entrada que recibe la neurona se calcula una suma ponderada agregando también el sesgo y de acuerdo con el resultado y una función de activación preestablecida (las cuales veremos a continuación), se decide la activación o excitación de la neurona. Posteriormente, la neurona transmite la información a otras neuronas conectadas en un proceso llamado «PassFoward». Al final de este proceso, la última capa oculta está vinculada a la capa de salida que tiene una neurona para cada posible salida deseada.


z = \sum_{i=1}^nX_iW_i + b_i

a = F(z)

Funciones de Activación

Se utiliza para determinar la salida de la red neuronal como sí o no. Mapea los valores resultantes entre 0 a 1 o -1 a 1 .Las funciones de activación se pueden dividir básicamente en 2 tipos:

  • Función de activación lineal : Las cuales ya no se usan en el Deep Learning, ya que la salida de las funciones no estará confinada entre ningún rango y la suma de diferentes funciones lineales sigue siendo una función lineal acotando así la activación de la neurona.
  • Funciones de activación no lineal: Son las usadas en las redes neuronales, como veremos a continuación estas funciones permiten un acotamiento de los datos de salida. Algunos ejemplos son al función sigmoide o tangente hiperbólica

Función Sigmoide

  • La razón principal por la que usamos la función sigmoide es porque existe entre (0 a 1). Por lo tanto, se usa especialmente para modelos en los que tenemos que predecir la probabilidad como un resultado. Dado que la probabilidad de cualquier cosa existe solo entre el rango de 0 y 1

sigmoide(x) = \frac{1}{1+e^{-x}}

sigmoide'(x) = x{(1-x)}

Función Tangente hiperbólica o Gaussiana

  • Es una función similar a la Sigmoide pero produce salidas en escala de [-1, +1]. Además, es una función continua. En otras palabras, la función produce resultados para cada valor de x.

cosh(x) = \frac{e^{-x} + e^{-x}}{2} 

tanh(x) = \frac{e^{-x} - e^{-x}}{e^{-x} + e^{-x}}  

tanh'(x) = \frac{1}{\cosh^2{x}} 

Función RELU (Rectified Lineal Unit)

  • ReLU es la función de activación más utilizada en el mundo en este momento. Desde entonces, se utiliza en casi todas las redes neuronales convolucionales o el aprendizaje profundo.
  • Como puedes ver, ReLU está medio rectificado (desde abajo). f(z) es cero cuando z es menor que cero y f(z) es igual a z cuando z es superior o igual a cero.
  • Es una función usada en las capas ocultas de nuestra red neuronal, NO en las de salida

relu(x) = \max(0,x)

relu'(x) = 1.(x>0)

Creamos las funciones en Python

¿Como aprende nuestra red neuronal?

El paso final del PassForward es evaluar la salida predicha (Yr) contra una salida esperada (Yr). La salida Yr es parte del conjunto de datos de entrenamiento (x, y) donde x es la entrada (como vimos en la sección anterior). La evaluación entre Yp e Yr se realiza a través de una función de coste. Para este ejercicio hemos usado dos funciones de coste:

  • MSE (error cuadrático medio)
  • Entropía cruzada binaria.

Llamamos a esta función de coste C y la denotamos de la siguiente manera:

C = cost(Y_p,Y_r)

Y_p= valor\ que\ ha\ predecido\ nuestra\ red

Y_r=valor\ real\ de\ los\ datos

Donde el cost puede ser igual a MSE, entropía cruzada o cualquier otra función de coste. Según el valor de C, el modelo «sabe» cuánto ajustar sus parámetros (Weight y BIAS) para acercarse a la salida esperada y. Esto sucede usando el algoritmo de retropropagación o tambien conocido como Backpropagation.

Funciones de coste y sus derivadas

MSE (Error cuadrático medio)

MSE = \frac{1}{n}{\sum_{1=1}^n{(Y_i - \hat{Y_i})}^2}

MSE´ = \sum_{i=1}^n{(Y_i - \hat{Y_i})}

Cross entropy binary

H(y,P) = \begin{cases}P=1, -\log(P)\\P=0, -\log(1-P)\end{cases}

Estas dos expresiones podemos juntarlas en una sola para obetener una unica función de coste

H(y,P) = -\frac{1}{n}{\sum_{1=1}^n}(y\log(P) + (1-y)\log(1-P))

H(y,P)´ =-(\frac{y}{P}-\frac{1-y}{1-P})"))

Funciones de perdida en Python

BackPropagation y gradiente descendente

Backpropagation tiene como objetivo minimizar la función de coste ajustando los pesos (w) y sesgos (bias) de la red. El nivel de ajuste está determinado por los gradientes de la función de coste con respecto a esos parámetros. (derivadas)

La derivada de una función C mide la sensibilidad al cambio del valor de la función (valor de salida) con respecto a un cambio en su argumento x (valor de entrada). En otras palabras, la derivada nos dice en qué dirección va C.

El gradiente muestra cuánto debe cambiar el parámetro x (en dirección positiva o negativa) para minimizar C.

Para calcular estos gradientes usamos la tecnica de la Regla de la cadena

Derivada de la función de Coste respecto al peso

  • Se puede expresar con la regla de la cadena, multiplicando la derivada del Coste respecto a la suma ponderada (z) por la derivada de (z) respecto al valor del peso (w)

\frac{\partial C}{\partial w^l_{jk}} =\frac{\partial C}{\partial z^l_j}\frac{\partial z^l_j}{\partial w^l_{jk}}

Por\ definición\ sabemos\ que\ : z^l_j=\sum_{k=1}^mw^l_{jk}a^{l-1}_{k}+b^l_{j}

Calculando\ la\ derivada\ podemos\ decir\ que :\frac{\partial z^l_j}{\partial w^l_{jk}} =a^{l-1}_{k}

Valor\ final :\frac{\partial C}{\partial w^l_{jk}} =\frac{\partial C}{\partial z^l_j}a^{l-1}_{k}

l = nº\ de\ capa

j = nº\ de\ neurona

Derivada de la función de Coste respecto al parametro BIAS

  • Se puede expresar con la regla de la cadena, multiplicando la derivada del Coste respecto a la suma ponderada (z) por la derivada de (z) respecto al valor del BIAS (b)

\frac{\partial C}{\partial b^l_{j}} =\frac{\partial C}{\partial z^l_j}\frac{\partial z^l_j}{\partial b^l_{j}}

Calculando\ la\ derivada\ podemos\ decir\ que :\frac{\partial z^l_j}{\partial b^l_{j}} =1

Valor\ final :\frac{\partial C}{\partial b^l_{j}} =\frac{\partial C}{\partial z^l_j}1

La parte común en ambas ecuaciones a menudo se denomina «gradiente local» y se expresa de la siguiente manera:

\delta^l_{j} =\frac{\partial C}{\partial z^l_{j}}

Regla\ de\ la\ cadena: \delta^l_{j} =\frac{\partial C}{\partial a^l_{j}}\frac{\partial a^l_{j}}{\partial z^l_{j}}

Computar el error de la capa anterior

\delta^{l-1} =\delta^lw^l\frac{\partial a^{l-1}}{\partial z^{l-1}}

Cuando ya tenemos el desarrollo de las variables parciales podemos ajustar los parametros de nuestra red

Actualizamos el parametro de BIAS usando el Vector Gradiente

'b_{l+1} =b_{l} - \epsilon\frac{\partial C}{\partial b}

\epsilon = El\ ratio\ de\ aprendizaje\ (Cuanto\ nos\ deplazamos\ en\ nuestra\ función\ de\ coste\ en\ cada\ iteración)

Actualizamos el parametro de pesos usando el vector Gradiente

w_{l+1} =w_{l} - \epsilon\frac{\partial C}{\partial w}

\epsilon = El\ ratio\ de\ aprendizaje\ (Cuanto\ nos\ deplazamos\ en\ nuestra\ función\ de\ coste\ en\ cada\ iteración)

Realizamos este proceso interativamente hasta que conseguimos minimizar el error en nuestra función de coste. Algoritmo del Gradiente Descendente

Programamos la Red neuronal en Python

Todo el proyecto disponible en:

https://github.com/jmcalvomartin/python/tree/master/projects/Create_ANN