En este primer post de una serie de tres, hablaremos de una de las ramas más importantes del Machine Learning y la Inteligencia Artificial, las redes neuronales. Abordaremos este tema desde cero, empezando por la historia de las redes neuronales, sus conceptos básicos, nos adentraremos en las matemáticas que están involucradas en ellas e implementaremos un ejemplo de Redes Neuronales desde cero para reconocer cierto tipo de patrones en imágenes.
Índice
Introducción
Las redes neuronales (neural networks) se enmarcan dentro del campo de la Inteligencia Artificial. En primer lugar, decir que hace unos 25 años prácticamente nadie sabía lo que era Internet ni su significado, como podéis comprobar en este vídeo del programa Today Show de 1994. Las redes neuronales se inventaron en los años 60, ¿qué ha ocurrido entonces?
Un poco de historia
En 1994, los ordenadores tenían una capacidad muy limitada . Este es el principal motivo por el cual las redes neuronales no fueron usadas en esa época, a pesar de ser inventadas décadas antes. Los ordenadores no tenían todavía la capacidad de cálculo. Tampoco la capacidad de tratamiento y almacenamiento de datos para trabajar con redes neuronales. Sin embargo, los años 70 y 80 están caracterizados por películas futuristas con robots y máquinas que toman el control.
En Terminator o Blade Runner, donde se ve claramente que el concepto de máquina inteligente estaba ya latente en aquella época. Lamentablemente, en las siguientes décadas, este interés se fue apagando. Aunque había una amplia investigación en las universidades sobre la Inteligencia Artificial. De hecho, se llegó a pensar que el mundo de las redes neuronales llegó a su fin. Era una bonita teoría pero sin posible aplicación práctica.
Sin embargo, el crecimiento en todo los sentidos de los ordenadores ha sido exponencial desde aquella época.
Aprendizaje Profundo o Deep Learning
Seguramente habéis visto muchas veces una imagen como la siguiente:
Deep Learning
con unas flechas de entrada a la izquierda, cierto cerebro las procesa y a partir de ese momento son transformadas en datos digitales:
El padre del concepto de Deep Learning fue el británico Geoffrey Hinton. Investigó sobre el Deep Learning en los años 80, actualmente trabaja en Google, y muchas cosas de las que hablaremos provienen de la nomenclatura de Geoffrey Hinton. La idea principal que hay detrás del concepto de Deep Learning es observar el cerebro humano e inspirarse en él para intentar reproducir de forma informática su comportamiento. Por lo tanto, si lo que intentamos es imitar el cerebro humano, tenemos que llevar ciertos elementos de la neurociencia al ordenador. Veamos cómo hacemos esto.
La Neurona humana
En la siguiente imagen podemos observar neuronas humanas en el microscopio.
Neuronas del cerebro humano
En ella podemos observar una especie de masa o cuerpo más o menos redondo. Además, vemos un núcleo o centro, y una serie de ramificaciones que se van extendiendo. En el cerebro, más o menos, tenemos unas cien mil millones de neuronas. Por lo tanto, lo que tratamos de hacer es trasladar el comportamiento del cerebro humano a una máquina, teniendo en cuenta que el conocimiento que tenemos del cerebro humano es todavía muy limitado.
Redes neuronales
Veamos entonces cómo pasamos de las neuronas que hay en el cerebro humano a formar una red neuronal en una máquina que simule su comportamiento.
La Neurona Artificial
Las neuronas artificiales se modelan de tal forma que imiten el comportamiento de una neurona cerebral. Tendrán unas ramificaciones y un núcleo o nodo. Habrá ramificaciones de entrada al nodo, que serán las entradas de la neurona, procedentes de otras neuronas. Esta información se procesará en un nodo, y se generará una información de salida que se trasmitirán por las ramificaciones de salida a otras neuronas. Podemos pensar en las conexiones entre neuronas artificiales como en las sinapsis de las neuronas del cerebro. La imagen de una típica neurona artificial es la siguiente.
Neurona artifical
La red neuronal
En la siguiente imagen podemos ver algunos modelos de redes neuronales.
Red Neuronal simple y Red Neuronal profunda.
Vemos que las ramificaciones de salida de algunas neuronas son las ramificaciones de entrada de otras, y así sucesivamente. Pero vemos un par de diferencias entre las capas. Las neuronas de color rojo no tienen ramificaciones de entrada. Son información que vamos a dar a las neuronas «desde el exterior», o «estímulo inicial». También vemos que las neuronas de color azul tiene ramificaciones de salida que no están conectadas a otras neuronas. Son la información de salida de la red neuronal o «estímulo final». Dependiendo del número de capas ocultas (amarillas) podemos hablar de una red neuronal simple o profunda.
Valores de salida y pesos de las redes neuronales
Los valores de salida pueden ser continuos, como el precio de una determinada compra. También pueden ser binarios, como por ejemplo si una persona va a padecer una enfermedad o no. O pueden ser una categoría, como la marca de coche que más se venderá el próximo año. En este contexto, el caso binario es un caso particular donde tenemos dos categorías.
Para poder llevar a cabo el procesado, cada sinapsis tendrá asignado un valor o peso. Equivalen a la «fuerza» de la señal que se trasmite por cada sinapsis. El ajuste de estos pesos para tener una red neuronal que haga lo que queremos es fundamental. Hablaremos de ello ampliamente cuando hablemos del entrenamiento de la red neuronal. Veremos métodos para ajustar estos pesos, como el descenso de gradiente y el backpropagation. Veamos entonces cómo se procesa la información dentro de cada neurona.
Procesado de información de una neurona artificial
Las señales de entrada que vemos en la imagen anterior son variables independientes, parámetros de entradas que serán procesados por el cuerpo de la neurona artificial para finalmente propagar el resultado a una señal de salida. Por lo tanto, la flechas de transmisión de las entradas hacia el núcleo de la neurona harían el papel de la sinapsis de las neuronas cerebrales. Tendemos entonces una capa de neuronas de entrada, una capa de neuronas ocultas (en la imagen una) y una capa de neuronas de salida (una o más).
Todas las variables independientes de la capa de entrada, pertenecen a una única observación, una única muestra, «un sólo registro de la base de datos».
En el núcleo de la neurona es donde se procesan las señales de entrada y los pesos. Una de las formas es multiplicar cada señal de entrada por su peso y sumarlo todo, es decir, hacer una combinación lineal de los pesos de las conexiones y las entradas
w_0 x_0 + w_1 x_1 + w_2 x_2 + … + w_N x_m
como vemos en el primer paso de la siguiente imagen. Posteriormente, se aplica una determinada función de activación al resultado del primer paso, y el resultado final se propaga a la salida, tercer paso de la imagen.
y = \phi(w_0 x_0 + w_1 x_1 + w_2 x_2 + … + w_N x_m)
Procesado de información en una neurona
Veamos las cuatro funciones de activación más típicas que suelen usarse.
Funciones de activación
Primero se calcula la combinación lineal de los pesos y las entradas. Las funciones de activación no son más que la manera de trasmitir esta información por las conexiones de salida. Puede que nos interese transmitir esa información sin modificar, por lo que usaríamos sin más la función identidad. En otros casos, quizás no queramos que se transmita información alguna. Es decir, transmitir un cero en las salidas de la neurona.
En general, las funciones de activación se utilizan para dar una «no linealidad» al modelo y que la red sea capaz de resolver problemas más complejos. Si todas las funciones de activación fueran lineales, la red resultante sería equivalente a una red sin capas ocultas.
Vamos a ver las cuatro familias de funciones de activación más usadas en redes neuronales.
Función escalón (threshold)
Como vemos en la figura de abajo, en el eje x está representado el valor ya ponderado de las entradas y sus respectivos pesos, y en el eje y tenemos el valor de la función escalón. Esta función propaga un 0 si el valor de x es negativo, o un 1 si es positivo. No hay casos intermedios, y sirve para clasificar de forma muy estricta. Es la función más rígida.
Función escalón
Función sigmoide
Como en la función escalón, existe una división entre los valores negativos y positivos de x, pero la función sigmoide no es tan estricta, el cambio se hace de manera suave. Se usa en la regresión logística, una de las técnicas más usadas en Machine Learning. Como vemos en la figura de abajo, la función no tiene aristas, es más suave (en términos matemáticos, es derivable). Cuanto más positivo es el valor de x más nos acercamos a 1 y por el contrario, cuanto más negativo es x más nos acercamos a 0.
Función sigmoide
Esta función es muy útil en la capa final de salida al final de la red neuronal, no solo para clasificar con valores categóricos, sino también para intentar predecir las probabilidades de pertenencia a cada categoría, donde sabemos que la probabilidad de un suceso imposible es 0 y la de un suceso seguro es 1.
Función rectificadora (ReLU)
Volvemos a tener en esta función una arista. Vemos en la figura de abajo que su valor es 0 para cualquier valor negativo de x. Si x es positivo la función retorna el propio valor de x. Por lo tanto, se obvian todas aquellas entradas que una vez ponderadas tienen un valor negativo y nos quedamos con el valor exacto de las positivas. Vemos también que, al contrario de las anteriores, los valores no se restringen a valores entre 0 y 1.
Función rectificadora
Función tangente hiperbólica
Esta función es muy parecida a la función sigmoidea, pero en este caso, como vemos en la figura de abajo, no empieza en 0 y termina en 1, sino que empieza en -1 y termina en 1.
Función tangente hiperbólica
Configuración de la red neuronal
Ya tenemos los ingrediente básicos para configurar una red neuronal. Una capa de neuronas de entrada, donde pasaremos información a la red a modo de estímulos, una capa de neuronas oculta, que se encargará del procesado de la información proporcionada por la capa de entrada, y una capa de salida que procesará la información proporcionada por la capa oculta para obtener el resultado final de la red neuronal para una entrada específica. Una posible configuración podría ser como la mostrada en la figura de abajo.
Ejemplo de configuración de una red neuronal
Decir que la ponderación de las señales de salida la hemos hecho con una combinación lineal, en la capa oculta usamos una función rectificadora y en la de salida usamos una función sigmodea. Podéis usar en vuestras redes neuronales cualquier otro tipo de función que mejor se ajuste al problema que hay que resolver, esto es sólo un ejemplo.
La elección un una función de activación u otra dependerá de varios factores. Uno de ellos es el rango de valores que queremos en la salida de la neurona. Si no hay restricciones en el rango, utilizaremos la función identidad que propagará en la salida el valor de entrada. Si la restricción es únicamente que el valor de salida debe ser positivo, sin límite de cantidad, elegiremos una función rectificadora. Quizás nos interese una salida binaria 1 y 0 para clasificar, por lo que elegimos, por ejemplo, la función escalón. Puede que usemos un algoritmo de aprendizaje que hace uso de derivadas. Entonces utilizaremos funciones de activación donde la derivada esté definida en todo el intervalo. Por ejemplo la sigmoidal o la tangente hiperbólica, teniendo en cuenta que son más costosas en términos computacionales.
La función de costes
Durante el entrenamiento, tenemos los valores de entrada y sabemos cuáles son sus respectivas salidas. Lo que queremos es ajustar los pesos para que la red neuronal aprenda, y que los valores de salida de la red se acerquen lo más posible a los valores reales conocidos. Veamos con un pequeño ejemplo el proceso completo.
Supongamos que queremos construir una red neuronal que, una vez entrenada, prediga el precio de una casa. Para ello, recolectamos los siguientes datos sobre miles de casas:
- Superficie
- Edad de la casa
- Número de dormitorios
- Distancia a la ciudad
Tendremos miles de registros en una base de datos, con información sobre las casas y su valor actual. Se inicializarán los pesos de las diferentes conexiones entre neuronas de alguna forma (ya veremos cómo). Empezaremos a introducir en la red los registros correspondientes a cada casa y, para cada uno de ellos, obtendremos un valor de salida que generalmente no serán iguales a los valores reales del precio de las casas.
La función de coste es una función que mide, en cierto modo, la «diferencia» entre el valor de salida y el valor actual. En este ejemplo usaremos el error cuadrático medio. Por supuesto, puede ser una función más compleja.
Alimentamos en diferentes iteraciones a la red neuronal con los mismos datos de entrenamiento que tenemos, y en cada iteración intentamos minimizar la función de coste. Es decir que la diferencia entre los valores de salida y los reales sean cada vez menores. Como los datos de entrada son los que son, sólo podemos conseguir esto ajustando los pesos de las conexiones entre neuronas al final de cada iteración.
Ejemplo red neuronal
Valor real – predicción
Resumiendo, al final de cada iteración, para cada piso se obtendrá un valor de salida (predicción) de la red neuronal. Este valor diferirá en una cantidad con respecto al valor real que medirá la función de costes.
Ahora, actualizaremos los pesos de las conexiones neuronales y retroalimentamos la red neuronal con los datos iniciales de los pisos. Se repite el proceso de nuevo y se van ajustando los pesos de forma que la función de costes sea cada vez menor.
Una manera de calcular la función de costes es como la que vemos en la figura de abajo. Calculamos el cuadrado de la diferencia entre el valor de salida y el real (evitando valores negativos) de cada casa. Luego sumamos el valor para todas las casas y dividirlo entre 2 (abordaremos las matemáticas en siguientes post).
Valores para la función de costes
Una vez finalizado el proceso, tendremos una red neuronal entrenada lista para predecir el precio de una casa suministrando los datos de esta. En general la red hará predicciones excelentes para datos que hemos usado para entrenarla. Pero para evaluar la calidad de predicción de la red neuronal es necesario usar datos que no hayan sido usados para optimizar los pesos de las conexiones de la red.
Resumen
Ya tenemos las nociones básicas de lo que es una red neuronal. Con toda la información que tenemos sobre un determinado problema, en nuestro caso precios de pisos, construimos una red neuronal que aprenda a partir de esos datos. Finalmente, la red será capaz de predecir correctamente cuando preguntemos por datos que la red nunca ha visto.
En este post hemos visto algunos conceptos matemáticos sencillos, como las funciones de activación. En el siguiente, nos adentraremos de verdad en las matemáticas que hay detrás de las redes neuronales. Las funciones de activación de las neuronas que hemos visto son muy importantes. Su correcta elección nos proporcionará una red neuronal que haga buenas predicciones. Básicamente, las funciones de activación que hemos visto devuelven, o bien un valor entre cero y uno, o bien el mismo valor de entrada si este es positivo (rectificadora).
En el siguiente post veremos cómo se ajustan los pesos de las conexiones de la red neuronal. Para empezar a trabajar con ejemplos de redes neuronales, no es necesario conocer las matemáticas en las que se basan. Pero hay ventajas en conocer las matemáticas que hay detrás de cualquier algoritmo de machine learning. Cuando los resultados no sean lo suficientemente buenos, podremos obtener ideas de cómo mejorar el rendimiento. Si no tenemos esta base matemática, no tendremos más remedio que conformarnos con el resultado que tenemos.
Veremos que el problema del ajuste de pesos «por fuerza bruta», es decir, probando todas las posibilidades y quedándonos con la mejor, es en la práctica imposible ya que tardaríamos millones de años de computación en encontrar la mejor solución. Sin embargo, las matemáticas nos permiten encontrar esta solución en un tiempo razonablemente corto.
Actualización: la segunda parte ya está disponible: Redes neuronales desde cero (II): algo de matemáticas
Créditos
Las imágenes de este artículo han sido reproducidas, con permiso, del Curso completo de Inteligencia Artificial con Python.
Acerca del autor
Este es un post invitado por José David Villanueva García. José David es Ingeniero Técnico en Informática de Sistema por la Universidad Rey Juan Carlos, Graduado en Matemáticas por la UNED, y Máster en Matemáticas Avanzadas por la UNED (Máster Thesis).
Actualmente trabaja como ingeniero en Darmstadt, Alemania, en diferentes proyectos para la ESA (European Space Agency) y EUMETSAT (European Organisation for the Exploitation of Meteorological Satellites).
Muy interesante, y bien explicado. ¿Y las siguientes entregas?
Hola Pablo, muchas gracias por tu comentario.
Problemas personales me tienen «fuera de combate» durante un tiempo, te pido disculpas por el retraso de las siguientes entregas, que espero escribir en breve y te resulten igual de interesantes.
Un saludo.
José David.
Super Educatuvo, pero prometiste dos partes más, no las he visto… jejeje
Buenos dias.
Ya tienen disponible la entrada, pido de nuevo disculpas, problemas personales retrasaron mucho tiempo la publicación.
Un saludo y espero que les guste.
Jose-David.
Buenas tardes Francisco J.
Os pido disculpas, espero que en breve pueda publicar la segunda parte, con la parte más matemática, aunque espero que resulte igual de interesante.
Un saludo.
José-David.
Buenos dias.
Ya tienen disponible la entrada, pido de nuevo disculpas, problemas personales retrasaron mucho tiempo la publicación.
Un saludo y espero que les guste.
Jose-David.
Excelente articulo, muchas gracias por compartir tus conocimientos.
Muchas gracias por este articulo y los links que añades.
Me gustaría hacerte una pregunta.. para el futuro de la IA y del machine learning,¿ recomendarías Python como lenguaje que todo el mundo debería de saber? o crees que se está desarrollando un lenguaje opensource mejor…
Muchas gracias.
Saludos.
Pedro
Buenos dias Pedro, y por supuesto disculpa el retraso.
Por supuesto que recomendaria el aprendizaje de Python para todo este tipo de temas, pero me gustaria recalcar que lo que verdaderamente es importante son los conceptos, mas que el propio lenguaje de programacion que por supuesto tiene que ser adecuado para el algoritmo que se va a programar.
Hoy en dia, me parece que Python es el mas idoneo.
Un saludo.
Jose David.
PD: disculpen los acentos y puntuacion, escribo con un teclado aleman.