El procedimiento era bastante simple, y trataba de comparar pixel por pixel la imagen con los diferentes patrones (conjunto de imágenes), que teníamos de ella. Pero esta aproximación tiene bastantes problemas en cuanto a eficiencia a la hora de dar una respuesta (hay que recorrerse entero el juego de datos), como a la hora de si habíamos desplazado algo el número en la imagen.
Una mejor manera como ya adelanté, es usando un algoritmo de machine learning muy conocido (de hecho data de hace 60 años) y que se está empleando bastante en la actualidad: las Redes Neuronales.
Una red neuronal es un intento matemático, de intentar aproximarse a la forma en la que el cerebro emplea las neuronas para procesar información. Para ello la red consta de neuronas:
Una neurona en este modelo, equivaldría a una función matemática (pero no nos asustemos, no entraremos a profundizar demasiado), de tal manera que tiene una serie de entradas y produce una salida.
Para generar la salida lo que hace la neurona es coger cada entrada y la multiplica por un peso (cada entrada por uno diferente) y lo suma.
Por ejemplo si la neurona de 3 entradas de la imagen, tiene como pesos internos (0.5, 0, 1) y como entrada le entra (1, 2, 3) la salida sería 0.5*1 + 0*2 + 3*1 = 3.5
Una vez que entendemos cómo funciona una neurona, podemos establecer que una red neuronal es un conjunto de neuronas asociadas entre ellas. La red recibe una serie de entradas, la procesa y emite una (o varias salidas).
Las redes neuronales tienen diferentes niveles de neuronas, (generalmente dos), y puede variar el número de neuronas en cada nivel.
Por ejemplo en esta red extraída de la wikipedia:
Es una red neuronal que tiene N entradas. En la primera capa (o primer nivel) hay m neuronas, y en la segunda capa (que se corresponde en la imagen con la capa de salida), solo hay una neurona.
Una vez analizado el concepto, vamos a ver cómo aplicarlo a nuestro problema:
- Nuestras imágenes tenían todas 64 pixels (8x8) por lo tanto nuestra red neuronal, la vamos a definir con 64 entradas.
- Como queremos diferenciar 10 números diferentes (0,1,2...9) estamos ante un problema de clasificación (es decir, queremos clasificar algo que no sabemos qué es, en un grupo en este caso uno de los números) vamos a poner 10 neuronas de salida. Estas neuronas siempre devolverán valores entre 0 y 1, y en el caso ideal todas las neuronas serán 0, menos la neurona del número identificado que será 1. Por ejemplo, si estamos mandando una imagen de un 3, en la red esperamos una salida: [0, 0, 0, 1, 0...] (tened en cuenta que empezamos en 0).
- Vamos a usar una capa intermedia de neuronas. En este caso el número de la capa intermedia (así como si queréis poner más capas) es algo que uno elige y va variando y probando. No hay una regla fija, aunque hay que poner suficientes neuronas para que la red se pueda adaptar al problema, pero tampoco es bueno sobrepasarse. En nuestro caso voy a poner 20 neuronas.
Por lo tanto una vez diseñada la red, tendría una pinta así:
(En realidad en la capa de entrada y en la capa intermedia se añadirían una entrada adicional siempre con un 1 por motivos de cálculo, pero en este dibujo y en la explicación no lo vamos a considerar para no liarnos).
Una vez tenemos diseñada nuestra red neuronal, sabiendo que estamos ante un problema de clasificación (otro tipo de problemas, podría ser de regresión, por ejemplo si calculáramos cuanto creemos que costará un piso en base a ciertas características), lo que vamos a hacer es a entrenarla.
Nosotros desconocemos los valores que tiene que tener cada neurona de la red para resolver nuestro problema (aquellos pesos de los que hablábamos cuando definíamos lo que es la neurona), por lo tanto vamos a emplear un algoritmo llamado backpropagation que lo que hace es ajustar los pesos de cada neurona de la red, para que la red "aprenda" a resolver nuestro problema.
Para ello escogemos un juego de entrenamiento (si os acordáis de la entrada anterior, ya teníamos uno):
Y entrenaremos la red, con este juego hasta que consideremos que se amolda lo suficiente a nuestro problema.
No vamos a entrar en los términos matemáticos que se usan en el algoritmo, para que resulte más sencillo de entender, pero lo que hace a grandes rasgos es:
- Primero se generan pesos para cada neurona de manera aleatoria.
- Se define una función de coste, que indica si estamos fallando mucho, o si estamos acertando mucho. Es decir cuanto valores más pequeños nos dé esa función (idealmente 0), más próximos estaremos de que la red se haya amoldado a nuestro problema.
- Se ejecuta todo el juego de pruebas sobre la red neuronal, y gracias al backpropagation (que por su complejidad matemática no describiremos aquí), se estima cuanto error está cometiendo cada una de las neuronas de la red y se ajustan sus pesos para tratar de minimizar ese error.
- Se ejecuta de nuevo el punto anterior N iteraciones, hasta que consideremos que la función de coste nos da valores suficientemente bajos que la red ya está amoldada al problema en un gran número de casos.
En la implementación que yo hice haciendo 400 iteraciones sobre la red, podemos ver como en cada iteración disminuye algo el coste:
![]() |
| Coste en la primera iteración |
![]() |
| Coste en la última iteración |
(Que no os líe, que el contador de Iteraciones va hacia abajo en lugar de hacia arriba)
Y al final una vez entrenada la red, podemos ver como la mayoría del juego de entrenamiento la red lo acierta, y que nos acierta el número que habíamos pintado en la entrad anterior:
Si os interesa el tema, no dejo de recomendaros el curso de Machine Learning de Coursera que da Andrew Ng que es muy recomendable.
Y si os interesa mi implementación del algoritmo y queréis cacharrear probando a cambiar los tamaños de cada capa, o ampliar el número de entradas para otro tipo de uso, (ojo que el algoritmo que minifica no es el ideal y hay librerías en casi todos los lenguajes que encontrarán la convergencia mejor) aquí está el repositorio de Github.
En las próximas entradas seguramente volvamos con este tema, aplicándolo a otro tipo de entradas o de problemas, e inclusó trataré de llevar una red ya entrenada a javascript para que podáis jugar con ella en vivo.







No hay comentarios:
Publicar un comentario