By: Daniel Ching
Las matemáticas detrás de las redes neuronales
Las redes neuronales forman el núcleo del aprendizaje profundo, un subconjunto del aprendizaje automático que presenté en mi artículo anterior. Las personas expuestas a la inteligencia artificial generalmente tienen una buena idea de alto nivel de cómo funciona una red neuronal: los datos se pasan de una capa de la red neuronal a la siguiente y estos datos se propagan desde la capa superior a la capa inferior hasta que, de alguna manera, , el algoritmo genera la predicción sobre si una imagen es la de un chihuahua o un muffin.
Parece magia, ¿no? Sorprendentemente, las redes neuronales para un modelo de visión por computadora pueden entenderse utilizando las matemáticas de la escuela secundaria . Solo requiere la explicación correcta de la manera más simple para que todos comprendan cómo funcionan las redes neuronales bajo el capó. En este artículo, utilizaré la base de datos de dígitos manuscritos del MNIST para explicar el proceso de creación de un modelo utilizando redes neuronales desde cero .
Antes de sumergirnos, es importante resaltar por qué necesitamos comprender cómo funcionan las redes neuronales bajo el capó. Cualquier aspirante a desarrollador de aprendizaje automático podría simplemente utilizar 10 líneas de código para diferenciar entre gatos y perros, entonces, ¿por qué molestarse en aprender lo que sucede debajo?
Esta es mi opinión: sin una comprensión completa de lo que son las redes neuronales en el aprendizaje automático, 1) nunca podremos personalizar completamente el código necesario y adaptarlo para diferentes problemas en el mundo real, y 2) la depuración será una pesadilla .
En pocas palabras, un principiante que usa una herramienta compleja sin comprender cómo funciona la herramienta sigue siendo un principiante hasta que comprenda completamente cómo funcionan la mayoría de las cosas.
En este artículo, cubriremos lo siguiente:
- Una descripción general amplia de cómo funcionan las predicciones de aprendizaje profundo
- Cumplir con los requisitos previos para importar y procesar los datos.
- Profundizar en los 7 pasos para crear un modelo de aprendizaje automático de una capa
- Creando múltiples capas usando la función de activación
Red neuronal: predicción generada por computadora
Para entender esto completamente, tenemos que volver al lugar donde se popularizó por primera vez el término “aprendizaje automático”.
Según Arthur Samuel , uno de los pioneros en inteligencia artificial y creador de uno de los primeros programas de autoaprendizaje exitosos del mundo, definió el aprendizaje automático como:
Supongamos que disponemos de algún medio automático para probar la eficacia de cualquier asignación de peso actual en términos de rendimiento real y proporcionamos un mecanismo para alterar la asignación de peso a fin de maximizar el rendimiento. No necesitamos entrar en los detalles de tal procedimiento para ver que podría hacerse completamente automático y ver que una máquina así programada “aprendería” de su experiencia.
A partir de esta cita, podemos identificar 7 pasos fundamentales en el aprendizaje automático. Tomado en el contexto de la identificación entre dos dígitos escritos a mano “2” o “9”:
- Inicializar los pesos
- Para cada imagen, use estos pesos para predecir si es un 2 o un 9.
- De todas estas predicciones, averigüe qué tan bueno es el modelo.
- Calcular el gradiente, que mide para cada peso, cómo cambiar el peso cambiaría la pérdida
- Cambiar todos los pesos según el cálculo
- Regrese al paso 2 y repita
- Repite hasta la decisión de parar.
Podemos visualizar el flujo de estos 7 pasos en el siguiente diagrama:
Sí, mirar esto puede ser un poco abrumador, ya que hay toneladas de jerga técnica nueva que puede resultar desconocida. ¿Qué son los pesos? ¿Qué son las épocas? Quédese conmigo, lo explicaré paso a paso a continuación. Es posible que estos pasos no tengan mucho sentido, pero ¡agárrate fuerte!
Los requisitos previos: importar, procesar los datos
Primero, hagamos todos los requisitos previos: importar los paquetes necesarios. Este es el paso más básico para comenzar a crear cualquier modelo de visión por computadora. Vamos a utilizar PyTorch, así como fast.ai . Dado que fast.ai es una biblioteca construida sobre PyTorch, este artículo explicará cómo se escriben algunas de las funciones integradas de fast.ai (por ejemplo, la clase del alumno en la línea 9 de la lista anterior).
de fastai.vision.all import * desde la importación de fastbook *
En segundo lugar, tomemos las imágenes del conjunto de datos MNIST . Para este ejemplo en particular, tenemos que recuperar los datos de los directorios de entrenamiento de los números escritos a mano 2 y 9.
Para descubrir lo que contiene la carpeta, podemos emplear el uso de los .ls () en fast.ai . Luego, abrimos las imágenes para ver cómo se ve-
Como puede ver, ¡es simplemente una imagen del número ‘2’ escrito a mano!
Sin embargo, las computadoras son incapaces de reconocer las imágenes que se les transmiten así; los datos en la computadora se representan como un conjunto de números. Podemos ilustrar eso en el ejemplo aquí:
Ahora bien, ¿qué representan todos estos números? Echemos un vistazo usando una función útil que nos proporcionan los pandas:
Como se muestra arriba, la forma principal en que las computadoras interpretan las imágenes es a través de la forma de píxeles, que son los bloques de construcción más pequeños de cualquier pantalla de computadora . Estos píxeles se registran en forma de números.
Ahora que tenemos una mejor comprensión de cómo la computadora realmente interpreta las imágenes, profundicemos en cómo podemos manipular los datos para dar nuestra predicción.
Estructuras de datos y conjuntos de datos
Antes incluso de calcular las predicciones, tenemos que asegurarnos de que los datos estén estructurados de la misma manera para que el programa procese todas las diferentes imágenes. Asegurémonos de tener dos tensores diferentes, cada uno para todos los ‘nueves’ y ‘dos’ en el conjunto de datos.
Antes de seguir avanzando, tenemos que discutir qué es exactamente un tensor . Escuché por primera vez sobre la palabra tensor en el nombre TensorFlow , que es una biblioteca (¡completamente!) Separada de la que estamos usando. Un tensor de PyTorch en este caso es una tabla multidimensional de datos, con todos los elementos de datos del mismo tipo . La diferencia entre listas o matrices y Tensores PyTorch es que estos tensores pueden finalizar los cálculos mucho (muchos miles de veces) más rápido que con las matrices Python convencionales.
Analizar todos los datos que hemos recopilado como datos de entrenamiento para el modelo no va a ser suficiente, simplemente porque necesitamos algo con lo que comparar nuestro modelo. No queremos que nuestro modelo sobreentrene o sobreajuste nuestros datos de entrenamiento, con un buen rendimiento en el entrenamiento, solo para romperse cuando encuentra algo que nunca antes había visto, fuera de los datos de entrenamiento. Por lo tanto, tenemos que dividir los datos en el conjunto de datos de entrenamiento y el conjunto de datos de validación .
Para hacer esto, hacemos:
Además, tenemos que crear variables, tanto variables independientes como variables dependientes, para permitir el seguimiento de dichos datos.
train_x = torch.cat ([stacked_twos, stacked_nines]). view (-1, 28 * 28)
Esta variable train_x contendrá todas nuestras imágenes como variables independientes (es decir, lo que queremos medir, piense: ¡ciencia de quinto grado!).
Luego creamos la variable dependiente, asignando el valor ‘1’ para representar los dos escritos a mano, con el valor ‘0’ para representar los nueves escritos a mano en los datos.
train_y = tensor ([1] * len (dos) + [0] * len (nueves)). desaprimir (1)
Luego creamos un conjunto de datos basado en las variables independientes y dependientes, combinándolas en una tupla, una forma de listas inmutables.
Luego repetimos el proceso para el conjunto de datos de validación:
Luego procedemos a cargar ambos conjuntos de datos en un DataLoader con el mismo tamaño de lote.
Ahora que hemos completado la configuración de nuestros datos, podemos continuar procesando estos datos con nuestro modelo.
Crear un modelo lineal de capa
Hemos completado la configuración de nuestros datos. Volviendo a los siete pasos del aprendizaje automático, podemos avanzar lentamente a través de ellos ahora.
Paso 1: inicializar los pesos
¿Qué son los pesos ? Los pesos son variables y una asignación de peso es una elección particular de valores para esas variables. Se puede pensar en el énfasis que se le da a cada punto de datos para que el programa funcione. En otras palabras, cambiar estos conjuntos de pesos cambiará el modelo para que se comporte de manera diferente para una tarea diferente.
Aquí, inicializamos los pesos de forma aleatoria para cada píxel:
Por favor, compruebe si falta algo de aquí -?
Juntos, los pesos y los sesgos (presentes porque los pesos a veces pueden ser cero, y queremos evitar eso) forman los parámetros.
Hubo algo que me molestó: ¿había una mejor manera de inicializar los pesos, en comparación con volcar un número aleatorio?
Resulta que la inicialización aleatoria en redes neuronales es una característica específica, no un error . En este caso, los algoritmos de optimización estocástica (que se explicarán a continuación) utilizan la aleatoriedad para seleccionar un punto de partida en la búsqueda antes de avanzar en la búsqueda.
Paso 2: Predicciones: para cada imagen, predice si es un 2 o un 9.
Luego podemos seguir adelante y calcular nuestra primera predicción:
A continuación, calculamos las predicciones para el resto de los datos utilizando mini lotes:
Este paso es crucial , debido a que tiene la capacidad de calcular las predicciones , y es una de las dos ecuaciones fundamentales de cualquier red neuronal.
Paso 3: utilizar la función de pérdida para comprender qué tan bueno es nuestro modelo
Para saber qué tan bueno es el modelo, tenemos que usar una función de pérdida . Esta es la cláusula “probar la efectividad de cualquier asignación de peso actual en términos de desempeño real”, y es la premisa sobre cómo el modelo actualizará sus pesos para brindar una mejor predicción.
Piense en una función de pérdida básica. No podemos usar la precisión como una función de pérdida porque la precisión solo cambiará si las predicciones de si una imagen es un ‘2’ o un ‘9’ cambian por completo; en ese sentido, la precisión no captará las pequeñas actualizaciones en la confianza o certeza con la que el modelo predice los resultados.
Lo que podemos hacer, sin embargo, es crear una función que registre la diferencia entre las predicciones que da el modelo (por ejemplo, da 0,2 para una predicción bastante segura de que la imagen que está interpretando está más cerca de 2 en lugar de 9) y la etiqueta real asociada con él (en este caso, sería 0, por lo tanto, la diferencia bruta, la pérdida , entre la predicción y el modelo sería 0.2).
¡Pero espera! Como se puede ver en la salida, no todas las predicciones w enfermos se encuentran en el rango entre 0 y 1 , algunos de ellos podrían estar muy lejos. Lo que queremos es otra función que pueda aplastar los valores entre 0 y 1.
Bueno, hay una función útil para esto: se llama función sigmoidea . Es una función matemática que viene dada por (1/1 + e ^ (- x)) que contiene todos los números, positivos y negativos entre 0 y 1.
La función Sigmoide es útil aquí porque podemos usar el enfoque de descenso de gradiente estocástico (siguiente sección) para calcular el gradiente de la curva en cualquier entrada.
Ahora, puede haber una idea errónea que algunas personas tienen cuando aprenden Machine Learning a través de videos introductorios; ciertamente, tuve algunos. Si busca en Google en línea, la función Sigmoide generalmente está mal vista, pero es importante conocer el contexto en el que se utiliza la función Sigmoide antes de criticarla. En este caso, se utiliza simplemente como una forma de comprimir los números entre 0 y 1 para la función de pérdida. Estamos no utilizamos sigmoide como una función de activación, que se discutirá más adelante.
Por lo tanto, podemos calcular la pérdida de nuestro mini-lote:
Paso 4: Cálculo del gradiente: el principio del descenso de gradiente estocástico
Dado que podemos comenzar con pesos dados (pesos aleatorios), el objetivo del modelo de aprendizaje automático es alcanzar la menor pérdida posible dentro de los límites de entrenamiento del modelo.
Esto puede parecer complejo, pero solo requiere matemáticas de la escuela secundaria para tener una buena comprensión de este concepto. Imagine que nuestra función de pérdida es una función cuadrática arbitraria y = x², y queremos minimizar esta función de pérdida. Pensaríamos inmediatamente en el punto donde la derivada o el gradiente de esta función es cero, que pasa a estar en el punto más bajo (o el “valle”). Dibujar una línea tangencial a la curva en ese punto nos daría una línea recta. Querríamos que el programa se actualizara constantemente para alcanzar ese punto mínimo.
Esta es una de las principales formas en que se minimizan las pérdidas en el aprendizaje automático y proporciona una descripción general amplia de cómo se acelera rápidamente el entrenamiento de modelos.
Para calcular los gradientes (no, no tenemos que hacerlo manualmente, por lo que no necesitaría buscar sus notas de matemáticas de la escuela secundaria), escribimos la siguiente función:
Paso 5: Cambiar los pesos según el gradiente calculado (escalonando los pesos)
Para cambiar los pesos de la función calc_grad, tendremos que escalonar la función de manera que nuestros valores se acerquen al mínimo de la función de pérdida. Lo hacemos con una pieza de código muy importante, como se muestra:Si has llegado hasta aquí, ¡eso es todo! Estos son los pasos en bruto escritos que se necesitan para entrenar el modelo una vez, de forma lineal. Los pasos 1 a 5 son los pasos fundamentales que se necesitan para revisar los datos una vez, y el período de ejecución de los datos una vez se llama “época”.
La diferencia entre el descenso de gradiente estocástico (SGD) y el descenso de gradiente (GD) es la línea “para xb, yb en dl” – SGD lo tiene, mientras que GD no. El descenso de gradiente calculará el gradiente de todo el conjunto de datos , mientras que SGD calcula el gradiente en mini lotes de varios tamaños.
Ahora, en aras de la simplicidad, consolidamos todas las demás funciones (validación, precisión) que hemos escrito en funciones de nivel superior y juntamos los distintos lotes:
Paso 6: repitiendo desde el paso 2
Luego pasamos todas nuestras funciones a un bucle for, repitiendo el proceso durante un cierto número de épocas hasta que nuestra precisión aumenta al nivel óptimo.
¡Hurra! Acabamos de construir una red lineal (de una capa) que puede entrenar, en muy poco tiempo, a un nivel de precisión increíble.
Para optimizar este proceso y reducir la cantidad de funciones de nivel inferior (y para hacer que nuestro código se vea un poco mejor, por supuesto), usamos las funciones predefinidas (por ejemplo, una clase llamada Learner ) que tienen la misma funcionalidad que la líneas de código antes.
Creando múltiples capas usando la función de activación
¿Cómo progresamos de un programa lineal en capas a una de las múltiples capas? La clave está en una simple línea de código:Esto se conoce como función de activación, una que combina dos capas lineales para convertirla en una red de dos capas.
En particular, esta función res.max también se conoce como unidad lineal rectificada (ReLU) , que es una forma elegante de decir “convierte todos los números negativos en cero y deja los números positivos como están”. Esta es una de esas funciones de activación, mientras que hay muchas otras, como Leaky ReLU, Sigmoid (mal visto para usarse específicamente como una función de activación ), tanh, etc.
Ahora que entendemos cómo combinar dos capas lineales diferentes, ahora podemos crear una red neuronal simple a partir de ella:Y luego finalmente podemos entrenar nuestro modelo usando nuestra red neuronal artificial de dos capas:
¡Lo que es aún más interesante es que incluso podemos ver qué imágenes está tratando de procesar el modelo en las diversas capas de esta arquitectura de red simple!
Conclusión
Comprender lo que hay dentro de una red neuronal artificial puede parecer abrumador al principio. Las redes neuronales son la clave para la personalización y la comprensión de qué partes del modelo fallaron si tenemos que construir un modelo desde cero. Lo que se necesita es simplemente determinación, una computadora que funcione y una comprensión muy rudimentaria de los conceptos matemáticos de la escuela secundaria para sumergirse profundamente en la inteligencia artificial.