Clasificación de Imágenes en Python

Crearemos una Convolutional Neural Network con Keras y Tensorflow en Python para reconocimiento de Imágenes.

En este artículo iremos directo al grano: veremos el código que crea la red neuronal para visión por computador. En un próximo artículo explicaré bien los conceptos utilizados, pero esta vez haremos un aprendizaje Top-down 😉

Ejercicio Propuesto: Clasificar imágenes de deportes

Para el ejercicio se me ocurrió crear “mi propio set MNIST” con imágenes de deportes. Para ello, seleccioné los 10 deportes más populares del mundo -según la sabiduría de internet- : Fútbol, Basket, Golf, Futbol Americano, Tenis, Fórmula 1, Ciclismo, Boxeo, Beisball y Natación (enumerados sin orden particular entre ellos).

Obtuve entre 5000 y 9000 imágenes de cada deporte, a partir de videos de Youtube (usando a FFMpeg!). Las imágenes están en tamaño <<diminuto>> de 21×28 pixeles en color y son un total de 77.000. Si bien el tamaño en pixeles puede parecer pequeño ES SUFICIENTE para que nuestra red neuronal pueda distinguirlas!!! (¿increíble, no?).

Entonces el objetivo es que nuestra máquina: “red neuronal convolucional” aprenda a clasificar -por sí sóla-, dada una nueva imagen, de qué deporte se trata.

Ejemplo de imágenes de los deportes más populares del mundo

Dividiremos el set de datos en 80-20 para entrenamiento y para test. A su vez, el conjunto de entrenamiento también lo subdividiremos en otro 80-20 para Entrenamiento y Validación en cada iteración (EPOCH) de aprendizaje.

Una muestra de las imágenes del Dataset que he titulado sportsMNIST. Contiene más de 70.000 imágenes de los 10 deportes más populares del mundo.

Requerimientos para realizar el Ejercicio

Necesitaremos por supuesto tener Python 3.6 y como lo haremos en una Notebook Jupyter, recomiendo tener instalada una suite como Anaconda, que nos facilitará las tareas.

Además instalar Keras y Tensorflow como backend. Puedes seguir este artículo en donde se explica como instalar todo el ambiente de desarrollo rápidamente.

Necesitarás descargar el archivo zip con las imágenes (están comprimidas) y decomprimirlas en el mismo directorio en donde ejecutarás la Notebook con el código. Al descomprimir, se crearán 10 subdirectorios con las imágenes: uno por cada deporte

Al código Python sin más!

Por más que no entiendas del todo el código sigue adelante, intentaré explicar brevemente qué hacemos paso a paso y en un próximo artículo se explicará cada parte de las CNN (Convolutional Neural Networks). También dejaré al final varios enlaces con información adicional que te ayudarán.

Esto es lo que haremos hoy:

  1. Importar librerías
  2. Cargar las 70.000 imágenes (en memoria!)
  3. Crear dinámicamente las etiquetas de resultado.
  4. Dividir en sets de Entrenamiento, Validación y Test
    • algo de preprocesamiento de datos
  5. Crear el modelo de la CNN
  6. Ejecutar nuestra máquina de aprendizaje (Entrenar la red)
  7. Revisar los resultados obtenidos

Empecemos a programar!:

1- Importar librerías

Cargaremos las libs que utilizaremos para el ejercicio.

2-Cargar las imágenes

Recuerda tener DESCOMPRIMIDAS las imágenes!!! Y ejecutar el código en el MISMO directorio donde descomprimiste el directorio llamado “sportimages” (contiene 10 subdirectorios: uno por cada deporte).

Este proceso plt.imread(filepath)  cargará a memoria en un array las 77mil imágenes, por lo que puede tomar varios minutos y consumirá algo de memoria RAM de tu ordenador.

leyendo imagenes de /Users/xxx/proyecto_python/sportimages/
Directorios leidos: 10
Imagenes en cada directorio [9769, 8823, 8937, 5172, 7533, 7752, 7617, 9348, 5053, 7124]
suma Total de imagenes en subdirs: 77128

3- Crear etiquetas y clases

Crearemos las etiquetas en labels , es decir, le daremos valores de 0 al 9 a cada deporte. Esto lo hacemos para poder usar el algoritmo supervisado e indicar que cuando cargamos una imagen de futbol en la red, ya sabemos que corresponde con la “etiqueta 6”. Y con esa información, entrada y salida esperada, la red al entrenar, ajustará los pesos de las neuronas.

Luego convertimos las etiquetas y las imágenes en numpy array con np.array()

Cantidad etiquetas creadas: 77128
0 golf
1 basket
2 tenis
3 natacion
4 ciclismo
5 beisball
6 futbol
7 americano
8 f1
9 boxeo
Total number of outputs : 10
Output classes : [0 1 2 3 4 5 6 7 8 9]

4-Creamos sets de Entrenamiento y Test, Validación y Preprocesar

Nótese la “forma” (shape) de los arrays: veremos que son de 21×28 y por 3 pues el 3 se refiere a los 3 canales de colores que tiene cada imagen: RGB (red, green, blue) que tiene valores de 0 a 255.

Preprocesamos el valor de los pixeles y lo normalizamos para que tengan un valor entre 0 y 1, por eso dividimos en 255.

Ademas haremos el “One-Hot encoding” con to_categorical()  que se refiere a convertir las etiquetas (nuestras clases) por ejemplo de fútbol un 6 a una salida de tipo (0 0 0 0 0 0 1 0 0 0) Esto es porque así funcionan mejor las redes neuronales para clasificar y se corresponde con una capa de salida de la red neuronal de 10 neuronas.
NOTA: por si no lo entendiste, se pone un 1 en la “sexta posición” del array y el resto en ceros, PERO no te olvides que empieza a contar incluyendo el cero!!! por eso la “etiqueta 6” queda realmente en la séptima posición.

Por último en este bloque, subdividimos los datos en 80-20 para test y entrenamiento con train_test_split()  y nuevamente en 80-20 el de training para obtener un subconjunto de validación.

Training data shape : (61702, 21, 28, 3) (61702,)
Testing data shape : (15426, 21, 28, 3) (15426,)
Original label: 0
After conversion to one-hot: [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.] (49361, 21, 28, 3) (12341, 21, 28, 3) (49361, 10) (12341, 10)

5 – Creamos la red (Aquí la Magia)

Ahora sí que nos apoyamos en Keras para crear la Convolutional Neural Network. En un futuro artículo explicaré mejor lo que se está haciendo. Por ahora “confíen” en mi:

  • Declaramos 3 “constantes”:
    • El valor inicial del learning rate INIT_LR
    • cantidad de epochs  y
    • tamaño batch de imágenes a procesar batch_size  (cargan en memoria).
  • Crearemos una primer capa de neuronas  “Convolucional de 2 Dimensiones” Conv2D() , donde entrarán nuestras imágenes de 21x28x3.
  • Aplicaremos 32 filtros (kernel) de tamaño 3×3 (no te preocupes si aún no entiendes esto!) que detectan ciertas características de la imagen (ejemplo: lineas verticales).
  • Utilizaremos La función LeakyReLU como activación de las neuronas.
  • Haremos un MaxPooling (de 2×2) que reduce la imagen que entra de 21×28 a la mitad,(11×14) manteniendo las características “únicas” que detectó cada kernel.
  • Para evitar el overfitting, añadimos una técnica llamada Dropout (se explicará en un futuro artículo)
  • “Aplanamos” Flatten()  los 32 filtros y creamos una capa de 32 neuronas “tradicionales” Dense()
  • Y finalizamos la capa de salida con 10 neuronas con activación Softmax, para que se corresponda con el “hot encoding” que hicimos antes.
  • Luego compilamos nuestra red sport_model.compile()  y le asignamos un optimizador (en este caso de llama Adagrad).

6-Entrenamos la CNN

Llegó el momento!!! con esta linea sport_model.fit()  iniciaremos el entrenamiento y validación de nuestra máquina! Pensemos que introduciremos miles de imágenes, pixeles, arrays, colores… filtros y la red se irá regulando sola, “aprendiendo” los mejores pesos para las más de 150.000 interconexiones para distinguir los 10 deportes. Esto tomará tiempo en un ordenador como mi Macbook Pro (del 2016) unos 4 minutos… puede parecer mucho o muy poco… según se lo mire. NOTA: podemos ejecutar este mismo código pero utilizando GPU (en tu ordenador o en la nube) y los mismos cálculos tomarían apenas segundos.

Por último guardamos la red YA ENTRENADA sport_model.save()  en un formato de archivo h5py ya que nos permitirá poder utilizarla en el futuro SIN necesidad de volver a entrenar (y ahorrarnos los 4 minutos de impaciencia!).

Train on 49361 samples, validate on 12341 samples
Epoch 1/6
49361/49361 [==============================] – 40s 814us/step – loss: 1.5198 – acc: 0.4897 – val_loss: 1.0611 – val_acc: 0.7136
Epoch 2/6
49361/49361 [==============================] – 38s 775us/step – loss: 1.2002 – acc: 0.6063 – val_loss: 0.8987 – val_acc: 0.7717
Epoch 3/6
49361/49361 [==============================] – 43s 864us/step – loss: 1.0886 – acc: 0.6469 – val_loss: 0.8078 – val_acc: 0.7977
Epoch 4/6
49361/49361 [==============================] – 41s 832us/step – loss: 1.0166 – acc: 0.6720 – val_loss: 0.7512 – val_acc: 0.8180
Epoch 5/6
49361/49361 [==============================] – 36s 725us/step – loss: 0.9647 – acc: 0.6894 – val_loss: 0.7033 – val_acc: 0.8323
Epoch 6/6
49361/49361 [==============================] – 40s 802us/step – loss: 0.9258 – acc: 0.7032 – val_loss: 0.6717 – val_acc: 0.8379

Vemos que tras 6 iteraciones completas al set de entrenamiento, logramos un valor de precisión del 70% y en el set de validación alcanza un 83%. ¿Será esto suficiente para distinguir las imágenes deportivas?

7-Resultados obtenidos

Ya con nuestra red entrenada, es la hora de la verdad: ponerla a prueba con el set de imágenes para Test que separamos al principio y que son muestras que nunca fueron “vistas” por la máquina.

15426/15426 [==============================] – 5s 310us/step
Test loss: 0.6687967825782881
Test accuracy: 0.8409179307662388

En el conjunto de Testing vemos que alcanza una precisión del 84% reconociendo las imágenes de deportes. Ahora podríamos hacer un análisis más profundo, para mejorar la red, revisando los fallos que tuvimos… pero lo dejaremos para otra ocasión (BONUS: en la Jupyter Notebook verás más información con esto!) Spoiler Alert: La clase que peor detecta, son las de Fórmula 1.

Puedes probar con esta imagen de Basketball y de Fútbol a clasificarlas. En mi caso, fueron clasificadas con éxito.
En mis pruebas, a veces confundía esta imagen de Fútbol con Golf… ¿Será por el verde del campo?

Conclusiones y promesa futura!

Creamos una red neuronal “distinta”: una red convolucional, que aplica filtros a las imágenes y es capaz de distinguir distintos deportes con un tamaño 21×28 pixels a color en tan sólo 4 minutos de entrenamiento.

Esta vez fuimos a la inversa que en otras ocasiones y antes de conocer la teoría de las redes específicas para reconocimiento de imágenes (las CNN) les he propuesto que hagamos un ejercicio práctico. Aunque pueda parecer contra-intuitivo, muchas veces este método de aprendizaje (en humanos!) funciona mejor, pues vuelve algo más dinámica la teoría. Espero que les hayan quedado algunos de los conceptos y los terminaremos de amoldar en un próximo artículo, que espero tener pronto… si mis hijos me lo permiten 😉

Suscripción al Blog

Recibe el próximo artículo con más teoría, prácticas y material para seguir aprendiendo Machine Learning!

Los recursos y… Más recursos

Y mientras escribo el próximo artículo para el blog en español…

Ya disponible: ¿Qué son las Convolutional Neural Networks y cómo funcionan? La Teoría que faltaba 🙂

…les dejo varios enlaces (que seguramente utilizaré como inspiración) con más información sobre las Convolutional Neural Networks:

Y por último MIS artículos sobre Redes Neuronales (en Español!!)

12 Replies to “Clasificación de Imágenes en Python”

  1. Hola Juan Ignacio,

    Qué interesante saber que existe este método de enseñanza top-botton. Precisamente días atrás estaba pensando que la dificultad para aprender AI para nosotros los programadores autodidactas desde tutoriales como el tuyo reside en que hay un concentrado de abstracciones muy difíciles de digerir, pues tratar de entender cada concepto abstraído resulta muy dispersivo.

    Entiendo, que de modo contrario explicar cada pequeño concepto resultaría muy complicado para el instructor y se corre el riesgo de no terminar nunca de mostrar aplicaciones practicas concretas como la que enseñas en esta entrada.

    Aquí es cuando quiero pedirte un consejo. Ya que mi principal interés de aprender AI reside en poder simplificar los conceptos bases de modo de poderle enseñar a niños con una metodología botton-top. ¿Cuales crees tú que son los conceptos bases que debo comenzar a investigar de modo de poder comenzar a recopilar contenido digerible más allá de un simple glosario?

    Agradezco nuevamente tus esfuerzos en hacernos llegar este conocimiento.

    1. Hola Germán, nuevamente gracias por participar del blog y escribirme!. Realmente no sé aconsejarte una mejor (ó peor) metodología de aprendizaje. Los conceptos más potentes para mi (y esto es muy subjetivo) son:

      • 1 -Definición de Machine Learning: la máquina aprende a generalizar conceptos por sí misma y la diferencia con la programación tradicional
      • 2 -Redes neuronales Artificiales “tradicionales” (perceptron y luego multilayer) Esto a mi particularmente me abrió la cabeza, el hecho de imitar nuestro comportamiento biológico, la función de activación y la interrelación entre neuronas
      • 3 -Deep Learning (y surgen las redes neuronales ya más potentes y con jerarquías en sus capas)

      Imagino que hay muchas otras variantes mejores, pero bueno, era por darte mi opinión.
      Saludos y espero haber podido ayudar un poco. Sigamos en contacto!

      1. Muchas gracias Juan Ignancio, no me llegó la notificación y hoy es que estoy leyendo tu respuesta.

        Sería interesante poder unir un equipo de trabajo para estudiar la mejor forma de al menos “comenzar a interesar” sobre la materia al público más joven posible. A mí me preocupa mucho la brecha tecnológica que se está abriendo en Latinoamérica, porque mucha de esa información, así como muchísima de la información del mundo de la programación, están disponible de forma “marginal” en español. Y yo considero que eso colocará en gran desventaja a muchísima gente en los próximos años. Evidentemente no me preocupo únicamente por niños o personas hispanohablantes, me gustaría que cualquier persona del mundo tenga un buen acceso a esta información, porque de ello dependerá el bienestar en áreas geográficas extensas. Pero es un trabajo titánico para una sola hormiga. En cualquier caso los desafíos son siempre motivantes. Yo estoy trabajando en un código open suorce para mostrar transparencia en la gestión de proyectos y de esta manera lograr financiar cursos (entre otras cosas) que estarían a disposición de cualquiera dentro de la plataforma. Es un proyecto que lo estoy iniciando pero le tengo bastante ilusión puesta. El repositorio lo encuentras aquí https://github.com/Chococoin/CrystalChocolate.

        De momento todos los recursos que estoy destinando salen de mi bolsillo y de mi tiempo. No tengo problema con eso, pero seguramente serán pocos los recursos que se puedan destinar a una sección pedagógica. Sin embargo, te invito a que discutamos mejor la forma en como podemos colaborar para ayudar a más personas a aprender todo esto.

        Un cordial saludo y gracias nuevamente por tu maravilloso blog.

  2. Hola Juan,

    Muy interesante el artículo.

    Ahora mismo estoy cursando IA en la UOC y estamos empezando con LISP. De momento, estoy alucinando un poco con la teoría y las prácticas, cuando tenga un rato miraré de configurar el entorno que propones y ejecutar tú código.

    ¡Un abrazo!

    1. Hola David!, gracias por estar siempre presente y compartiendo tus experiencias!
      A decir verdad me tendrás que enseñar LISP tu a mi! Abrazo!

  3. gracias por el tiempo , y los conocimientos.. , podrías subir algo de identificación de figuras geométricas utilizando imagenes en tensorflow.

    1. Hola, pues deberías crear un dataset con imágenes como las que quieras identificar y entrenar tu red (CNN). Eso o necesitaría más detalle de lo que pretendes hacer. Hay otra temática además de la clasificación de imágenes -que escribí en este artículo- que es la “detección de objetos” dentro de la imagen. Te dejo un enlace por si te sirve: Object Detection a Guide.

  4. Hola Excelente articulo, he visto las CNN con MatLab pero no en Python, un par de preguntas:

    Has pensado en usar por defecto la GPU dedicada cuando exista para que sea mas rapido el entrenamiento????

    Sabes como hacer Transfer Learning de otra red ya entrenada tipo AlexNet con Python??

    Saludos desde mexico

    1. Hola Angel, gracias por escribir, espero que el blog sea de tu ayuda para usar CNN en Python. Mi próximo artículo comentaré mejor la teoría. Te respondo:
      Al instalar el backend de tensorflow eliges si funcionará con CPU ó GPU. Si tienes, es lo mejor, pues se acelera el training de minutos a apenas segundos. Una tercer opción es usar Algún servicio en la Nube que corra con GPU. La mayoría son servicios de pago, pero ahora google ofrece un servicio limitado que sellaba Colab.
      Puedes hacer Transfer learning, tanto Keras como Pytorch ofrecen hacer un “load” de esas redes pre-entrenadas para ajustarlas a tus propios intereses. Te recomiendo sobre todo que veas/uses la lib de fast.ai pues está muy enfocada en el uso “rápido” de CNN que ya vienen pre-entrenadas.

  5. Hola Juan Ignacio.
    Muy interesante, lo que pasa es que en el soprtimages.zip no hay las 70.000 imágenes, sólo hay dos directorios.
    ¿Es correcto?.
    Gracias

    1. Hola Jose, el archivo zip contiene 10 subdirectorios con los deportes y cada uno contiene más de 5000 imágenes. Imagino que habrás tenido algún problema con la descarga. Saludos

Leave a Reply to INSTITUTO TECNOLOGICO SUPERIOR ZACATECAS OCCIDENTE Cancel reply