Últimamente he visto unos cuantos malentendidos sobre las redes neuronales y también recuerdo que hace varios años la primera vez que me topé con ellas me parecieron un tanto misteriosas y no ayudaba mucho que la mayoría de textos introductorios que leí en aquel entonces no parecían mostrar razones muy sólidas para usarlas.
Lo más común que veía era una combinación de las siguientes razones:
- Actúan parecido a las neuronas del cerebro, entonces no es de extrañar que funcionen.
- Son bastante robustas al procesar información con ruido.
- No necesitas entender el problema, nomás lanzar datos de entrenamiento y solas hacen todo.
- Hay un teorema que díce que las redes neuronales pueden aprender cualquier función continúa
La verdad no me atraía la idea de estar usando una caja negra que probablemente sería menos eficiente que programar un algoritmo manualmente; y sobre el último punto, también hay teoremas que dicen que cualquier función continua se puede aproximar por polinomios, o que cualquier función continua periódica se puede aproximar usando senos.
...y si bien lo de procesar información con ruido sonaba bien, tampoco me quedaba claro por qué éso podría ser mejor que entrenar otros modelos de aprendizaje (de preferencia algunos que no fueran tan misteriosos).
Sin embargo, recientemente tras estudiar unas cuantas fuentes, ya soy capaz de entender el potencial que tienen estas herramientas y quería compartir ésto.
¿Imitan a la biología?
Primero que nada quiero desmentir un malentendido que se ha estado propagando bastante, y es la idea de que las redes neuronales imitan al cerebro humano. El único parecido que tienen(además del nombre) es que en ambos casos reciben información de conexiones con sus símiles, realizan una operación sencilla y producen una salida.
Mas allá de ésa similitud en la unidad más pequeña de ambas redes, no se parecen en nada más. Las conexiones de las redes neuronales artificiales se entrenan en base a un montón de ejemplos para que dadas ciertas entradas produzcan ciertas salidas, pero en ningún momento se intenta imitar la estructura de un cerebro.
Incluso, me atrevo a hacer notar que un transistor se parece más a una neurona biológica que una neurona de red neuronal artificial(porque tanto el transistor como la neurona biológica reciben señales eléctricas de entrada y producen señales eléctricas de salida, pero las redes neuronales artificiales son puro software en lugar de operar directamente con señales físicas).
Clasificadores Lineales
Esto podría parecer que no tiene nada que ver con las redes neuronales, pero prometo que tendrá sentido más adelante.
Los clasificadores lineales son un tipo de método de aprendizaje automático bastante clásico, la idea es que conocen 2 conjuntos de puntos, que pertenecen a 2 clases distintas, se espera que en el futuro se van a recibir más puntos, pero con estos otros va a ser necesario intentar identificar a qué clase pertenecen (es decir, la clase ya no va a ser conocida con los puntos provistos en el futuro).
Aunque nos vamos a imaginar a los puntos como coordenadas en un plano, en la práctica los puntos pueden representar cualquier conjunto de rasgos numéricos. Como las dimensiones de un terreno, datos demográficos de una persona o incluso los datos de los colores de los pixeles de imágenes.
Un clasificador lineal lo que hace es encontrar una recta que separe lo mejor posible a ambos conjuntos y luego asumir que todo lo que llegará de un lado de la recta pertenecerá a una clase y lo que llegue del otro lado pertenecerá a la otra clase.
En el siguiente ejemplo, la recta
Divide el plano en 2 mitades:
Otra forma de entenderlo, y que será importante más adelante, es que los puntos que están dentro de un semiplano los agrupa en una clase y los que están fuera del semiplano los agrupa en la otra clase. Suena que es una cuestión puramente semántica, pero tener presente el conjunto del semiplano será importante.
Cuando los datos de entrada contienen 3 variables, el problema se convierte en encontrar un plano que divida al espacio en 2 mitades, lo cual se puede ver como elegir los puntos que estén en la región del espacio que satisfaga:
Extrapolando la generalización a vectores de cualquier tamaño es bastante directa:
De esta manera, es posible generalizar los clasificadores lineales a vectores de cualquier tamaño. Existen varias maneras para entrenar estos clasificadores, pero no ahondaré en ello ya que lo que nos importa ahora es su relación con las redes neuronales.
Compuertas lógicas
Otro elemento importante en este contexto son las compuertas lógicas. Se trata de componentes electrónicos que implementan lógica básica en circuitos digitales.
Estas compuertas operan tomando señales eléctricas de entrada, con 2 posibles intensidades y transformándolas en una señal eléctrica de salida según las reglas de la lógica booleana.
Las compuertas más comunes son:
- Compuerta AND: Produce un 1 solo si todas sus entradas son 1.
- Compuerta OR: Produce un 1 si al menos una de sus entradas es 1.
- Compuerta NOT (inversor): Invierte el valor de la entrada. Si la entrada es 0, la salida es 1, y viceversa.
- Compuerta XOR (OR exclusivo): Produce un 1 si las entradas son diferentes
¿Por qué son tan importantes las compuertas lógicas?
Debido a que todo algoritmo, por complejo que sea, puede descomponerse en una serie de pasos lógicos y artiméticos. Estos pasos, a su vez, pueden expresarse en términos de operaciones booleanas, es decir, con valores verdadero o falso. Aquí es donde las compuertas lógicas entran en juego: son herramientas que nos permiten manipular estos valores binarios para realizar cálculos y tomar decisiones.
Hay un teorema conocido como el teorema de la completitud funcional, que implica que cualquier función lógica puede implementarse utilizando solo un conjunto pequeño de compuertas (como AND, OR y NOT). Esto incluye desde operaciones aritméticas básicas hasta algoritmos sofisticados.
Combinando Compuertas Lógicas y Clasificadores Lineales
¿Cómo se relacionan estas 2 herramientas que acabamos de examinar?, pues para averiguarlo habrá que revisitar los conceptos de unión, intersección y complemento de lógica y conjuntos.
- La unión de 2 conjuntos A y B se refiere coloquialmente a tomar los elementos de A y luego agregarle los elementos de B. Lo interesante es que matemáticamente se define como: un elemento está en la unión de A y B, si está presente en A o está presente en B.
- La intersección de 2 conjuntos A y B puede entenderse como lo que tienen en común ambos conjuntos, y se define matemáticamente como: un elemento está en la intersección de A y B, si está en A y además también está en B.
Como ya vimos anteriormente, un clasificador líneal clasifica los puntos dependiendo de si están dentro o fuera de un semiplano. Ahora, ¿qué pasa si queremos agrupar una clase como los puntos que estén dentro de uniones o interesecciones de semiplanos?, con éso podríamos hacer un clasificador con cualquier polígono, ¡por más lados que contenga!, incluso podríamos usar cualquier conjunto de polígonos aunque fueran disjuntos.
Por ejemplo, en el siguiente clasificador:
Podemos pensar en la clase 0 como:
$$A \cup (B \cap C)$$
Donde tanto A, como B como C se pueden obtener a partir de un clasificador lineal.En cierta manera el clasificador mostrado en la imagen se podría expresar con el siguiente árbol:
Con estos mismos componentes podríamos hacer clasificadores más complicados, por ejemplo esto:
...podría lograrse con el siguiente clasificador:
Esta misma lógica se podría extender la clasificación a más variables. Incluso es posible demostrar que cualquier región de un espacio de cualquier dimensión delimitada por una frontera continua puede ser aproximada arbitrariamente por esta clase de composiciones de clasificadores lineales.
En este momento puede que estés pensando algo así como: "Los clasificadores lineales son útiles porque se pueden entrenar, pero, al combinarse con compuertas lógicas, ¿cómo se entrenan?, además, ¿tengo que saber de antemano qué compuertas lógicas usar y en qué configuración ponerlas antes de entrenarlas?"
...y es de mi agrado responder a éso con una buena noticia: ya existe un modelo que puede hacer todo lo que hacen esta combinación de compuertas lógicas y clasificadores lineales, y además puede entrenarse con decenso de gradiente sin necesidad de elegir explícitamente las compuertas lógicas.
Este modelo son las redes neuronales.
Neuronas como Clasificadores Lineales
Una red neuronal es un grafo acíclico dirigido de unas unidades que llamaremos neuronas. Podemos pensar en una neurona como un clasificador lineal pero que en lugar de regresar sólo 0 o 1 (dependiendo de si el punto se encuentra en el semi-plano/semi-espacio), puede regresar un número mayor que 0 y menor que 1 si se encuentra cerca de la frontera.
Es decir, para este clasificador:
En lugar de asignar 0 si \(x_1 + x_2 - 0.5 < 0\) y asignar 1 en otro caso, podríamos asignar clase 0.5 cuando \(x_1 + x_2 - 0.5 = 0\) y que conforme el valor de \(x_1 + x_2\) se vaya volviendo mucho mayor que 0, entonces la clase se va volviendo cercana a 1, y de manera análoga si el valor de \(x_1 + x_2\) es muy negativo entonces la clase se vuelve muy cercana a -1.
La ventaja de esta aproximación es que permite usar descenso de gradiente para entrenar este pequeño clasificador, y más importante aún ¡la salida del clasificador se puede usar como entrada de otros clasificadores!, y la composición de los clasificadores puede seguir funcionando con descenso de grandiente.
Hay muchas funciones que se pueden utilizar para este propósito, pero una muy popular es el sigmoide, o \(\sigma\).
$$\sigma(x) = \frac{1}{1 + e^{-x}}$$
...y su gráfica es la siguiente:
La neurona entonces consiste de un clasificador que recibe un vector \(x\) de entrada, y calcula un único número como salida dado por $$z = \sigma(x \cdot w - b)$$ ... donde w es un vector y b es un número, ambos dependen de la neurona y se ajustan durante el proceso de entrenamiento.
Este mismo clasificador lineal \(x_1+x_2 < 0.5\) puede expresarse con la siguiente neurona:
...sin embargo, tal vez puedas darte cuenta que como \(\sigma(-1)\) ≈ 0.22 , si interpretamos ése número como una probabilidad, el clasificador se estaría mostrando demasiado inseguro para puntos que están cerca de la recta. Quizá te gustaría que fuera más tajante y tener \(a<0.1\) si \(x_1+x_2-0.5 < 1\) , pues bien, afortunadamente éso se puede hacer.
Basta con tomar \(w_1=10\), \(w_2=10\) y \(b=-5\), es decir, multiplicar todos los parámetros por 10, para que así \(a=\sigma(-10)\) en lugar de \(\sigma(-1)\). Esto es el equivalente a cambiar la aplastar horizontalmente la función de activación:
...y la neurona quedaría así (nótese que es la misma desigualdad para clasificar, pero los valores de \(a\) convergen mas rápido a 0 o a 1):
Las Neuronas como Compuertas Lógicas
Como había mencionado anteriormente, las neuronas también se pueden usar como compuertas lógicas, aquí podemos ver cómo hacerlo (recuerda que basta con multiplicar los pesos y la constante b para hacer que los valores se parezcan más a los valores discretos cuando z está cerca de 0).
Recomiendo probar manualmente los casos para asimilar bien esta información, recuerda que se asume que la entrada son números entre 0 y 1, muy cercanos a 0 o a 1.
Por último, la compuerta lógica XOR también se puede representar con neuronas pero hace falta más de una neurona, ya que los puntos \((0, 1), (1, 0)\) no se pueden separar de los puntos \((1, 1), (0, 0)\) con una única recta.
Una posible manera de resolver este problema es usando 2 rectas en lugar de una sola:
Queremos incluir lo que esté por debajo de la recta azul o por encima de la recta verde.
Esto se puede lograr utilizando 2 neuronas \(h_1\) y \(h_2\) para representar los 2 clasificadores lineales y una neurona más para expresar el OR:
Una red neuronal, como ya se había mencionado anteriormente, simplemente consiste en conectar varias neuronas sin formar ciclos, sin embargo, es bastante común organizar las redes neuronales en capas, de manera que cada capa sólo utilice como entrada las salidas de la capa anterior, algo así:
La ventaja de esta organización, es que los resultados de cada capa se pueden calcular a través de una multiplicación de matrices (y luego aplicar la función de activación).
El uso de GPUs ha facilitado bastante las operaciones con matrices, y esta es otra gran ventaja que tienen las redes neuronales, el hecho de que puedan aprovechar al máximo la potencia de los GPUs para poder entrenarse y ejecutarse.
Así que en resúmen, las redes neuronales son una herramienta de aprendizaje automático que permite aprender el comportamiento de:
- Clasificadores lineales.
- Compuertas lógicas
- Composiciones de las anteriores
- Clasificar cualquier región delimitada con fronteras continuas
- Cualquier algoritmo dados los datos suficientes
...y además aprovechan al máximo los GPUs.
¿...y Cómo se Entrenan?
Ya mencioné anteriormente que con descenso de gradiente, 3Blue1Brown tiene algunos videos donde explica éso muy bien qué es éso:
...si de casualidad llegaste hasta aquí sin estar muy instruido en matemáticas, ¡pues felicidades por tu perseverancia!, y aquí hay una breve explicación de la idea base sobre cómo entrenarlas:
Inicialmente se eligen los valores de las w (es decir, los pesos de las conexiones) al azar, y dados los datos de entrenamiento (ejemplos de diferentes entradas con la salida que deberían producir), se mide que tan lejos está la red de producir los resultados deseados.
Luego se observa en qué dirección al mover los valores de las w el comportamiento de la red se acerca más a los resultados deseados y se mueven un poco los valores de las w en ésa dirección.
Se repite este proceso hasta que se deja de notar mejoría o se pasa cierto tiempo pre-definido.