Codifiquemos una red neuronal desde cero - Parte 1

Parte 1, Parte 2 y Parte 3

Hay algo particularmente interesante en una computadora que aprende a hacer una tarea simple, con la probabilidad de que algún día supere las capacidades humanas.

Este tutorial tiene como objetivo enseñar a los codificadores creativos cómo crear una red neuronal artificial (ANN). Para ser un poco más específico, nuestra red consistirá en neuronas y perceptrones que se alimentarán y utilizarán la propagación hacia atrás para aprender. Esto puede sonar extraño para usted, pero no tema, explicaré todo en detalle. También es ANN en su forma más simple, por lo tanto, no esperes un desafío Tensorflow, su belleza radica en su simplicidad. Requiere cierta familiaridad con la programación orientada a objetos (OOP).

Utilizaremos el popular conjunto de datos MNIST de dígitos escritos a mano para entrenar la red y finalmente reconocer cada uno de ellos. Puede usar su idioma preferido, sin embargo, le recomiendo Procesar por su facilidad de uso y capacidades gráficas que nos ayudarán a comprender lo que está sucediendo.

Como nota al margen, si tengo lectores con experiencia en inteligencia artificial, me interesaría saber si se puede mejorar el rendimiento sin agregar demasiada complejidad o bibliotecas.

Conjunto de datos NMIST - Imagen de Adam Geitgey

¿Cómo funciona nuestro cerebro?

Primero exploremos dónde se origina ANN: nuestros cerebros. Al ver una señal de límite de velocidad "70", los fotones que rebotan desde los faros hacia el panel y de regreso a la retina producen una reacción química. Algunas de las neuronas conectadas a su corteza visual se excitarían y pasarían la señal a otras neuronas a través de una red de dendritas que libera una señal química.

Neuron Signal @ GIF de DynamicScience

Eventualmente, la actividad crece en los lóbulos occipital y temporal (áreas para interpretar información visual) y hace que te des cuenta de que estás superando el límite de velocidad. Por lo tanto, los fotones se procesan a través de una serie de capas que conducen a una acción correcta, en este caso reduciendo su velocidad.

Con nuestra comprensión elemental de la función cerebral, procedamos a explorar la estructura de la NN que estamos a punto de construir. Podemos abstraer el concepto antes mencionado mediante la construcción de un conjunto de neuronas "Entradas" que representan la retina, esto tomará la forma de una cuadrícula de píxeles. La información se pasa a una capa "oculta" que representa las capas dentro de nuestro cerebro. Finalmente, esta capa oculta se conecta a una capa de salida, el equivalente a las neuronas motoras que causaron la desaceleración.

Observe cómo cada neurona dentro de cada capa no está vinculada entre sí a diferencia de nuestro cerebro. Más bien, están vinculados a todas las neuronas en la siguiente capa. Esto explica la naturaleza de avance de nuestra red, los datos se pasan a través de las capas de manera directa.

En cuanto al tamaño de las matrices en cada capa, se han mantenido lo más pequeñas posible para que la red se pueda ejecutar en cualquier computadora portátil. Cada dígito (entrada) se representa como una cuadrícula de 14x14 píxeles (ver más abajo) que Alasdair Turner redujo su tamaño de 28x28. La capa oculta consiste en una cuadrícula de 7x7, esta es una opción completamente arbitraria y te animo a que juegues con esto una vez que tengas todo funcionando. Por último, nuestra salida es una serie de 10 neuronas, cada una de las cuales indica un posible dígito de 0 a 9.

Escrito a mano

En lugar de tener neuronas en cada capa, también tendremos perceptrones. El propósito de estos es tomar la suma de las entradas y si está por encima de un umbral dado, entonces "disparará". Observe cómo se pondera cada entrada, las que tienen un número mayor (flecha en negrita) significan un vínculo más fuerte entre las neuronas. En este caso, pasará el 90% (0.9 * 100) de la señal.

Escribamos un código

Con lo básico fuera del camino, vamos a estructurar nuestro programa, puede replicar esto en Procesamiento abriendo una pestaña para cada uno de los siguientes segmentos.

  1. Pestaña principal: Esto nos permitirá dibujar, "entrenar" y "probar" nuestra red neuronal.
  2. Cargar datos: esta pestaña nos permitirá cargar un conjunto de "tarjetas flash" etiquetadas. Cada tarjeta flash tendrá un número escrito a mano para que la red neuronal lo reconozca, y una etiqueta en la parte posterior para indicarnos qué número es en realidad.
  3. Neurona: Este será el código para un perceptrón individual como se muestra arriba.
  4. Red: constará de una serie de matrices de neuronas. Uno para la capa de entrada, uno para la capa oculta y otro para la capa de salida.
  5. Sigmoide: el propósito de esta pestaña es construir una función de "cómo disparar una neurona". Más detalles sobre esto en la parte 2.

Cargando los datos

Lo primero que debemos hacer es cargar los datos y mostrarlos como una cuadrícula. Vamos a referirnos ahora a cada punto como una neurona, observe cómo están en escala de grises. Diremos que la neurona no solo estará encendida o apagada, sino que estará dentro de un rango de +1 (negro, encendido), 0 (gris, parcialmente encendido / apagado) y -1 (blanco, apagado). A diferencia de nuestro cerebro, permanecerán en el estado en el que se establecieron por última vez.

El conjunto de datos completo contiene 10,000 dígitos escritos, lo dividiremos en dos para que tengamos un conjunto de entrenamiento de 8,000 dígitos y un conjunto de prueba de 2,000 dígitos. Al entrenar la red, usaremos la etiqueta numérica correspondiente para “enseñarla”. Al realizar la prueba, las tarjetas se utilizarán como una pregunta de "examen" para que su computadora vea si puede adivinar correctamente. No se le dará la solución correcta.

No creo que valga la pena cubrir cómo importamos los datos que se presentan como un conjunto de valores de bytes sin procesar, es secundario a la función del algoritmo. También puede encontrar la referencia completa en la base de datos NMIST sobre cómo procesarla. Vale la pena señalar que cada dígito se representa como un objeto de la clase "Tarjeta". Todos se cargan utilizando la función "loadData ()" que se llama antes que nada en "setup ()" y reside fuera de la clase "Card"

La entrada que es una cuadrícula de 14x14 nos da 196 entradas que se almacenan en una matriz simple. La salida también se almacena como una matriz de 10 respuestas posibles, como +1 si corresponde a la salida de -1 si no es así. También almacenaremos la etiqueta como una simple copia de seguridad numérica de las salidas utilizando la variable "etiqueta".

Clase de entrada y neurona

Ahora hemos cubierto cómo cargar nuestros datos, vamos a referirnos a cada círculo dibujado en la pantalla como una neurona.

Comenzaremos con una clase muy simple "Neuron" con una función de visualización.

El cálculo resaltado dentro de "fill ()" escala un número de +1 a -1 a un número 0 y 255. También hay una inversión para lograr un efecto de lápiz (negro) y papel (blanco). Las neuronas de disparo tienen un valor cercano a +1 que queremos dibujar como negro o un valor de alrededor de 0 como negro / gris, dependiendo de la fuerza.

Creemos también una clase de "Red" que usaremos para construir cada capa. Tiene tres funciones:

  • Red: Este es el inicializador, aquí configuramos una red con un número dado de entradas, en este caso será 196 (una por cada píxel).
  • Responder: aquí respondemos a una tarjeta que se muestra, por ahora solo copiaremos la entrada de la tarjeta a la salida de la tarjeta sin ningún cálculo.
  • Pantalla: Esto se usa para dibujar nuestras 196 neuronas como una cuadrícula de 14x14

Poner todo junto en nuestra pestaña principal nos da algo como esto:

En esta pestaña principal solo utilizamos la clase "Red", se inicializa en "setup ()" con 196 entradas (14x14). Luego alimentamos el conjunto de pruebas con un "cardNum" aleatorio que se genera con una pulsación del mouse.

El código completo para cargar y mostrar los datos se puede encontrar en GitHub. Solo recuerde incluir los datos, que se pueden agregar arrastrándolos a su boceto de procesamiento.

Si estás disfrutando esto, por favor presiona el

Ir a la parte 2

Algoritmo original de Alasdair Turner