Entendiendo Las Redes Neuronales

Tony Yiu
Aug 13, 2020

Entendiendo Las Redes Neuronales

Aug 13, 2020 19 minutes read

Exploramos cómo funcionan las redes neuronales para construir una comprensión intuitiva del aprendizaje profundo


El aprendizaje profundo es un tema de moda en estos días. Pero, ¿qué es lo que lo hace especial y lo diferencia de otros aspectos del aprendizaje automático? Esa es una pregunta profunda (perdón por el juego de palabras). Para empezar a responderla, necesitaremos aprender los fundamentos de las redes neuronales.

Las redes neuronales son los caballos de batalla del aprendizaje profundo. Y mientras que pueden parecer cajas negras, en el fondo (perdón, dejaré los terribles juegos de palabras) están tratando de lograr lo mismo que cualquier otro modelo: hacer buenas predicciones.

En este post, exploraremos los entresijos de una red neuronal simple . Y para el final, esperamos que usted (y yo) hayamos obtenido una comprensión más profunda e intuitiva de cómo las redes neuronales hacen lo que hacen.

Lea también: 

Una vista a 30.000 pies de altura

Empecemos con una visión general de alto nivel para saber con qué estamos trabajando. Las redes neuronales son redes multicapa de neuronas (los nodos azules y magenta en el gráfico de abajo) que usamos para clasificar cosas, hacer predicciones, etc. A continuación se muestra el diagrama de una red neuronal simple con cinco entradas, 5 salidas y dos capas ocultas de neuronas.

Red neuronal con dos capas ocultas

Empezando por la izquierda, tenemos:
  1. La capa de entrada de nuestro modelo en naranja.
  2. Nuestra primera capa oculta de neuronas en azul.
  3. Nuestra segunda capa oculta de neuronas en magenta.
  4. La capa de salida (también conocida como la predicción) de nuestro modelo en verde.

Las flechas que conectan los puntos muestran cómo todas las neuronas están interconectadas y cómo los datos viajan desde la capa de entrada hasta la capa de salida.

Más adelante calcularemos paso a paso cada valor de salida. También veremos cómo la red neuronal aprende de su error usando un proceso conocido como propagacion hacia atras.

Obteniendo nuestras orientación

Pero primero vamos a orientarnos. ¿Qué es exactamente intentando hacer la red neuronal? Como cualquier otro modelo, está tratando de hacer una buena predicción. Tenemos un conjunto de entradas y un conjunto de valores objetivo, y estamos tratando de obtener predicciones que coincidan con esos valores objetivo lo más cerca posible.

Olvida por un segundo la imagen más complicada de la red neuronal que dibujé arriba y concéntrate en la más simple de abajo.
Regresión logística (con una sola característica) implementada a través de una red neuronal

Esta es una una regresión logística de una sola característica (le estamos dando al modelo sólo una variable X) expresada a través de una red neuronal (si necesita un repaso de la regresión logística, he escrito sobre eso aquí). Para ver cómo se conectan podemos reescribir la ecuación de regresión logística usando los códigos de color de nuestra red neuronal.
Ecuación de regresión logística

Examinemos cada elemento:

  1. X (en naranja) es nuestra entrada, la única característica que le damos a nuestro modelo para calcular una predicción.
  2. B1 (en turquesa, también conocido como verde aguamarina) es el parámetro de la pendiente estimada de nuestra regresión logística - B1 nos dice por cuánto cambian las probabilidades logaritmicas a medida que cambia X. Noten que B1 vive en la línea turquesa, que conecta la entrada X con la neurona azul en la Capa Oculta 1.
  3. B0 (en azul) es el sesgo - muy similar al término de intercepción de la regresión. La diferencia clave es que en las redes neuronales, cada neurona tiene su propio término de sesgo (mientras que en la regresión, el modelo tiene un término de intercepción singular).
  4. La neurona azul también incluye una función de activación del sigmoide (denotada por la línea curva dentro del círculo azul). Recuerda que la función sigmoide es lo que usamos para ir de las probabilidades logarítmicas a las probabilidades (haz una búsqueda de control-f de "sigmoide" en mi entrada anterior).
  5. Y finalmente obtenemos nuestra probabilidad prevista aplicando la función sigmoide a la cantidad (B1*X + B0).

No está mal, ¿verdad? Así que recapitulemos. Una red neuronal super sencilla consiste en sólo los siguientes componentes:

  • Una conexión (aunque en la práctica, generalmente habrá múltiples conexiones, cada una con su propio peso, que va a una neurona en particular), con un peso "que vive dentro de ella", que transforma su entrada (usando B1) y se lo da a la neurona.
  • Una neurona que incluye un término de sesgo (B0) y una función de activación (sigmoide en nuestro caso).

Y estos dos objetos son los bloques de construcción fundamentales de la red neuronal. Las redes neuronales más complejas son sólo modelos con más capas ocultas y eso significa más neuronas y más conexiones entre neuronas. Y esta red más compleja de conexiones (y pesos y sesgos) es lo que permite a la red neuronal "aprender" las complicadas relaciones ocultas en nuestros datos.

Añadamos un poco de complejidad ahora


Ahora que tenemos nuestro marco básico, volvamos a nuestra red neuronal ligeramente más complicada y veamos cómo va de la entrada a la salida. Aquí está de nuevo como referencia:
Nuestra red neural ligeramente más compleja

La primera capa oculta consiste en dos neuronas. Así que para conectar las cinco entradas a las neuronas de la capa oculta 1, necesitamos diez conexiones. La siguiente imagen (abajo) muestra solo la conexión entre la Entrada 1 y la Capa Oculta 1.


Las conexiones entre la Entrada 1 y la Capa Oculta 1

Observe nuestra notación para los pesos que viven en las conexiones - W1,1 denota el peso que vive en la conexión entre la Entrada 1 y la Neurona 1 y W1,2 denota el peso en la conexión entre la Entrada 1 y la Neurona 2. Así que la notación general que seguiré es Wa,b denota el peso en la conexión entre la Entrada a (o Neurona a) y la Neurona b.

Ahora vamos a calcular las salidas de cada neurona en la Capa Oculta 1 (conocida como las activaciones). Lo hacemos usando las siguientes fórmulas (W denota peso, In denota entrada).

Z1 = W1*In1 + W2*In2 + W3*In3 + W4*In4 + W5*In5 + Bias_Neuron1
Activación de la neurona 1 = Sigmoide (Z1)
Podemos utilizar la matemática matricial para resumir este cálculo (recuerde nuestras reglas de notación - por ejemplo, W4,2 denota el peso que vive en la conexión entre la Entrada 4 y la Neurona 2):

La matemática matricial hace nuestra vida más fácil

Para cualquier capa de una red neural donde la capa anterior es m elementos de profundidad y la actual es n elementos de profundidad, esto se generaliza a:

[W] @ [X] + [Bias] = [Z]

Donde [W] en  su matriz de pesos n por m (las conexiones entre la capa anterior y la capa actual), [X] es su matriz m por 1 de entradas iniciales o activaciones de la capa anterior, [Sesgo] es su matriz n por 1 de sesgos neuronales, y [Z] es su matriz n por 1 de salidas intermedias. En la ecuación anterior, sigo la notación Python y uso @ para denotar la multiplicación de la matriz. Una vez que tenemos [Z], podemos aplicar la función de activación (sigmoide en nuestro caso) a cada elemento de [Z] y eso nos da nuestras salidas neuronales (activaciones) para la capa actual.

Finalmente, antes de seguir adelante, vamos a mapear visualmente cada uno de estos elementos de nuevo en nuestro gráfico de red neuronal para atarlo todo ([Sesgo] está incrustado en las neuronas azules).

Visualizando [W], [X] y [Z]

Calculando repetidamente [Z] y aplicándole la función de activación para cada capa sucesiva, podemos pasar de la entrada a la salida. Este proceso se conoce como propagación hacia adelante. Ahora que sabemos cómo se calculan las salidas, es el momento de empezar a evaluar la calidad de las mismas y de entrenar nuestra red neuronal.

Hora de que la red neuronal aprenda

Este va a ser un post largo, así que siéntase libre de tomar un descanso para el café ahora. ¿Sigues conmigo? ¡Impresionante! Ahora que sabemos cómo se calculan los valores de salida de una red neuronal, es hora de entrenarla.

El proceso de entrenamiento de una red neuronal, a un alto nivel, es como el de muchos otros modelos de ciencia de datos - definir una función de costo y usar la optimización de descenso de gradiente para minimizarlo.

Primero pensemos qué palancas podemos tirar para minimizar la función de coste. En la regresión lineal o logística tradicional buscamos coeficientes beta (B0, B1, B2, etc.) que minimicen la función de costo. Para una red neuronal, estamos haciendo lo mismo pero a una escala mucho mayor y más complicada.

En la regresión tradicional, podemos cambiar cualquier beta en particular de forma aislada sin afectar a los otros coeficientes beta. Así que aplicar pequeños choques aislados a cada coeficiente beta y medir su impacto en la función de coste, es relativamente sencillo para averiguar en qué dirección tenemos que movernos para reducir y eventualmente minimizar la función de coste.

Regresión logística de Cinco características implementadas a través de una red neuronal

En una red neuronal, cambiar el peso de una conexión cualquiera (o el sesgo de una neurona) tiene un efecto reverberante en todas las demás neuronas y sus activaciones en las capas subsiguientes.

Eso es porque cada neurona en una red neuronal es como su propio pequeño modelo. Por ejemplo, si quisiéramos una regresión logística de cinco características, podríamos expresarla a través de una red neuronal, ¡utilizando sólo una neurona singular!

Así que cada capa oculta de una red neuronal es básicamente una pila de modelos (cada neurona individual en la capa actúa como su propio modelo) cuyas salidas alimentan a más modelos más abajo (cada capa oculta sucesiva de la red neuronal contiene aún más neuronas).

La función de coste

Así que dada toda esta complejidad, ¿qué podemos hacer? En realidad no es tan malo. Vayamos paso a paso. Primero, permítanme establecer claramente nuestro objetivo. Dado un conjunto de entradas de entrenamiento (nuestras características) y resultados (el objetivo que estamos tratando de predecir):

Queremos encontrar el conjunto de pesos (recordemos que cada línea de conexión entre dos elementos cualesquiera de una red neuronal alberga un peso) y sesgos (cada neurona alberga un sesgo) que minimicen nuestra función de costo - donde la función de costo es una aproximación de cuán equivocadas son nuestras predicciones en relación con el resultado objetivo.

Para entrenar nuestra red neuronal, usaremos el Error Medio Cuadrado (MSE) como la función de coste:

MSE = Suma [ ( Predicción - Actual )² ] * (1 / num_de_observaciones)
El MSE de un modelo nos dice en promedio cuán equivocados estamos pero con un giro - al elevar al cuadrado los errores de nuestras predicciones antes de promediarlas, castigamos las predicciones que están muy lejos mucho más severamente que las que están sólo ligeramente lejos. Las funciones de coste de la regresión lineal y la regresión logística operan de manera muy similar.

Bien, genial, tenemos una función de costo para minimizar. Es hora de iniciar el gradiente descendente, ¿verdad?

No tan rápido - para usar el gradiente descendente, necesitamos saber el gradiente de nuestra función de costo, el vector que apunta en la dirección de la mayor inclinación (queremos tomar repetidamente pasos en la dirección opuesta del gradiente para eventualmente llegar al mínimo).

Excepto en una red neuronal tenemos tantos pesos y sesgos cambiantes que están todos interconectados. ¿Cómo calcularemos el gradiente de todo eso? En la siguiente sección, veremos cómo la propagación hacia atras nos ayuda a tratar este problema.

Revisión rápida del descenso del gradiente

El gradiente de una función es el vector cuyos elementos son sus derivadas parciales con respecto a cada parámetro. Por ejemplo, si intentáramos minimizar una función de coste, C(B0, B1), con sólo dos parámetros modificables, B0 y B1, el gradiente sería:

Gradiente de C(B0, B1) = [ [dC/dB0], [dC/dB1] ]

Así que cada elemento del gradiente nos dice cómo cambiaría la función de coste si aplicáramos un pequeño cambio a ese parámetro en particular, para que sepamos qué ajustar y por cuánto. En resumen, podemos marchar hacia el mínimo siguiendo estos pasos:

Ilustración del gradiente descendiente

  1. Calcular el gradiente de nuestra "ubicación actual" (calcular el gradiente usando los valores de nuestros parámetros actuales).
  2. Modificar cada parámetro en una cantidad proporcional a su elemento de gradiente y en la dirección opuesta a su elemento de gradiente. Por ejemplo, si la derivada parcial de nuestra función de coste con respecto a B0 es positiva pero diminuta y la derivada parcial con respecto a B1 es negativa y grande, entonces queremos disminuir B0 en una cantidad diminuta y aumentar B1 en una cantidad grande para disminuir nuestra función de coste.
  3. Recalcular el gradiente usando nuestros nuevos valores de parámetros ajustados y repetir los pasos anteriores hasta que lleguemos al mínimo.

Propagación hacia atras

Me remito a este gran libro de texto (¡en línea y gratis!) para la matemática detallada (si quieres entender las redes neuronales más profundamente, definitivamente échale un vistazo). En su lugar haremos lo mejor para construir una comprensión intuitiva de cómo y por qué funciona la propagación hacia atrás.
Recuerde que la propagación hacia adelante es el proceso de avanzar a través de la red neuronal (desde las entradas hasta la última salida o predicción). La propagación hacia atrás es lo contrario. Excepto que en lugar de señal, estamos moviendo el error hacia atrás a través de nuestro modelo.

Algunas visualizaciones simples ayudaron mucho cuando trataba de entender el proceso de propagación hacia atrás. Abajo está mi imagen mental de una simple red neuronal mientras se propaga hacia adelante de la entrada a la salida. El proceso se puede resumir en los siguientes pasos:

  • Las entradas se introducen en la capa azul de las neuronas y se modifican por los pesos, el sesgo y el sigmoide de cada neurona para obtener las activaciones. Por ejemplo: Activación_1 = Sigmoide( Sesgo_1 + W1*Entrada_1 )
  • La Activación 1 y la Activación 2, que salen de la capa azul, se introducen en la neurona magenta, que las utiliza para producir la activación de salida final.

Y el objetivo de la propagación hacia adelante es calcular las activaciones en cada neurona para cada capa oculta sucesiva hasta que llegamos a la salida.


Propagación hacia adelante en una red neuronal

Ahora vamos a invertirlo. Si sigues las flechas rojas (en la imagen de abajo), te darás cuenta de que ahora estamos empezando en la salida de la neurona magenta. Esa es nuestra activación de salida, que usamos para hacer nuestra predicción, y la última fuente de error en nuestro modelo. Luego movemos este error hacia atrás a través de nuestro modelo por medio de los mismos pesos y conexiones que usamos para propagar hacia adelante nuestra señal (así que en lugar de la Activación 1, ahora tenemos el Error1 - el error atribuible a la neurona azul de la parte superior).

¿Recuerdas que dijimos que el objetivo de la propagación hacia adelante es calcular las activaciones de las neuronas capa por capa hasta llegar a la salida? Ahora podemos establecer el objetivo de la propagación hacia atrás de manera similar:

Queremos calcular el error atribuible a cada neurona (me referiré a esta cantidad de error como el error de la neurona porque decir "atribuible" una y otra vez no es divertido) empezando por la capa más cercana a la salida hasta llegar a la capa inicial de nuestro modelo.


La propagación hacia atrás en una red neuronal

Entonces, ¿por qué nos preocupamos por el error de cada neurona? Recuerde que los dos bloques de construcción de una red neuronal son las conexiones que pasan las señales a una neurona en particular (con un peso que vive en cada conexión) y la propia neurona (con un sesgo). Estos pesos y sesgos a través de toda la red son también los diales que ajustamos para cambiar las predicciones hechas por el modelo.

Esta parte es realmente importante:

La magnitud del error de una neurona específica (en relación con los errores de todas las demás neuronas) es directamente proporcional al impacto de la producción de esa neurona (también conocida como activación) en nuestra función de coste.

Por lo tanto, el error de cada neurona es un sustituto de la derivada parcial de la función de costo con respecto a las entradas de esa neurona. Esto tiene sentido intuitivo - si una neurona en particular tiene un error mucho mayor que todas las demás, entonces ajustar los pesos y el sesgo de nuestra neurona infractora tendrá un mayor impacto en el error total de nuestro modelo que jugar con cualquiera de las otras neuronas.

Y las derivados parciales con respecto a cada peso y sesgo son los elementos individuales que componen el vector de gradiente de nuestra función de coste. Así que básicamente la propagación hacia atrás nos permite calcular el error atribuible a cada neurona y eso a su vez nos permite calcular las derivadas parciales y en última instancia el gradiente para que podamos utilizar el descenso del gradiente. ¡Hurra!

Una analogía que ayuda - El juego de la culpa
Es mucho para digerir, así que espero que esta analogía ayude. Casi todo el mundo ha tenido un colega terrible  en algún momento de su vida - alguien que siempre jugaba el juego de la culpa y tiraba a sus compañeros o subordinados debajo del autobús cuando las cosas iban mal.

Las neuronas, a través de la propagación hacia atrás, son las dueñas del juego de la culpa. Cuando el error se propaga hacía atrás a una neurona en particular, esa neurona rápida y eficientemente señalará con el dedo al colega (o colegas) de la parte superior que es más culpable de causar el error (es decir, las neuronas de la capa 4 señalarían con el dedo a las neuronas de la capa 3, las neuronas de la capa 3 a las neuronas de la capa 2, y así sucesivamente).
Las neuronas culpan a las neuronas más activas de flujo en la parte superior

¿Y cómo sabe cada neurona a quién culpar, ya que las neuronas no pueden observar directamente los errores de otras neuronas? Sólo miran quién les envió la mayor señal en términos de las más altas y frecuentes activaciones. Al igual que en la vida real, los perezosos que juegan a lo seguro (activaciones bajas e infrecuentes) patinan sin culpa mientras que las neuronas que hacen el mayor trabajo son culpadas y se les modifica el peso y los sesgos. Cínico sí, pero también muy efectivo para llevarnos al conjunto óptimo de pesos y sesgos que minimizan nuestra función de costo. En la imagen se ve de cómo las neuronas se lanzan unas a otras debajo del autobús.

Y eso en pocas palabras es la intuición detrás del proceso de propagación hacia atrás. En mi opinión, estas son las tres claves para la propagación hacia atrás:

  1. Es el proceso de desplazar el error hacia atrás capa por capa y atribuir la cantidad correcta de error a cada neurona de la red neuronal.
  2. El error atribuible a una neurona en particular es una buena aproximación de cómo el cambio de los pesos de esa neurona (de las conexiones que conducen a la neurona) y el sesgo afectarán a la función de coste.
  3. Al mirar hacia atrás, las neuronas más activas (las no perezosas ) son las que se ven culpadas y ajustadas por el proceso de propagación hacia atrás.

Juntando todo

Si ha leído hasta aquí, entonces tiene mi gratitud y admiración (por su persistencia).

Empezamos con una pregunta, "¿Qué hace especial al aprendizaje profundo?" Intentaré responder a eso ahora (principalmente desde la perspectiva de las redes neuronales básicas y no de sus primos más avanzados como las CNN, RNN, etc.). En mi humilde opinión, los siguientes aspectos hacen que las redes neuronales sean especiales:

  • Cada neurona es su propio modelo en miniatura con su propio sesgo y conjunto de características y pesos entrantes.
  • Cada modelo/neurona individual alimenta a otras numerosas neuronas individuales a través de todas las capas ocultas del modelo. Así que terminamos con modelos conectados a otros modelos de una manera en la que la suma es mayor que sus partes. Esto permite que las redes neuronales encajen en todos los rincones de nuestros datos, incluyendo las partes no lineales (pero cuidando el sobreajuste - y definitivamente considere la regularización para proteger su modelo de un bajo rendimiento cuando se enfrente a datos nuevos y fuera de muestra).
  • La versatilidad del enfoque de muchos modelos interconectados y la capacidad del proceso de propagación hacia atrás para establecer de manera eficiente y óptima los pesos y sesgos de cada modelo permite que la red neural "aprenda" de manera robusta a partir de los datos de maneras que muchos otros algoritmos no pueden.
Nota del autor: Las redes neuronales y el aprendizaje profundo son temas extremadamente complicados. Aún estoy en una etapa temprana del proceso de aprendizaje sobre ellas. Este blog fue escrito tanto para desarrollar mi propio entendimiento como para ayudarte a ti, el lector. Espero todos sus comentarios, sugerencias y retroalimentación. Salud!

Más por mí en Temas de Ciencias de la Información:

Fuentes:


Join our private community in Discord

Keep up to date by participating in our global community of data scientists and AI enthusiasts. We discuss the latest developments in data science competitions, new techniques for solving complex challenges, AI and machine learning models, and much more!