Reconocimiento y clasificación de imágenes en Python con TensorFlow y Keras

TensorFlow es un marco de aprendizaje profundo bien establecido y Keras es su API oficial de alto nivel que simplifica la creación de modelos. Reconocimiento de imagen/c...

Introducción

TensorFlow es un marco de aprendizaje profundo bien establecido, y Keras es su API oficial de alto nivel que simplifica la creación de modelos El reconocimiento/clasificación de imágenes es una tarea común y, afortunadamente, es bastante sencillo y sencillo con Keras.

En esta guía, veremos cómo clasificar/reconocer imágenes en Python con Keras.

{.icon aria-hidden=“true”}

Si desea jugar con el código o simplemente estudiarlo un poco más a fondo, el proyecto se carga en [GitHub](https://github.com/wikihtp/sa-image-recognition-keras/blob/main /SA-ImageRecognition.ipynb).

In this guide, we'll be building a custom CNN and training it from scratch. For a more advanced guide, you can leverage Transfer Learning to transfer knowledge representations with existing highly-performant architectures - read our Clasificación de imágenes con aprendizaje por transferencia en Keras - Cree modelos CNN de última generación!

Definiciones

Si no tiene claros los conceptos básicos detrás de la clasificación de imágenes, será difícil comprender completamente el resto de esta guía. Entonces, antes de continuar, tomemos un momento para definir algunos términos.

TensorFlow/Difícil

TensorFlow es una biblioteca de código abierto creada para Python por el equipo de Google Brain. TensorFlow compila muchos algoritmos y modelos diferentes juntos, lo que permite al usuario implementar redes neuronales profundas para usar en tareas como reconocimiento/clasificación de imágenes y procesamiento natural del lenguaje. TensorFlow es un marco poderoso que funciona mediante la implementación de una serie de nodos de procesamiento, cada nodo representa una operación matemática, y la serie completa de nodos se denomina "gráfico".

En términos de Keras, es una API (interfaz de programación de aplicaciones) de alto nivel que puede usar las funciones de TensorFlow debajo (así como otras bibliotecas ML como Theano). Keras fue diseñado con la facilidad de uso y la modularidad como principios rectores. En términos prácticos, Keras hace que la implementación de las muchas funciones poderosas pero a menudo complejas de TensorFlow sea lo más simple posible, y está configurado para funcionar con Python sin modificaciones ni configuraciones importantes.

Clasificación de imágenes (reconocimiento)

Reconocimiento de imagen se refiere a la tarea de ingresar una imagen en una red neuronal y generar algún tipo de etiqueta para esa imagen. La etiqueta que genera la red corresponderá a una clase predefinida. Puede haber varias clases con las que se puede etiquetar la imagen, o solo una. Si hay una sola clase, a menudo se aplica el término "reconocimiento", mientras que una tarea de reconocimiento de varias clases a menudo se denomina "clasificación".

Un subconjunto de la clasificación de imágenes es la detección de objetos, donde las instancias específicas de los objetos se identifican como pertenecientes a una determinada clase, como animales, automóviles o personas.

Extracción de características {#extracción de características}

Para llevar a cabo el reconocimiento/clasificación de imágenes, la red neuronal debe realizar extracción de características. Las características son los elementos de los datos que le interesan y que se alimentarán a través de la red. En el caso específico del reconocimiento de imágenes, las características son los grupos de píxeles, como bordes y puntos, de un objeto que la red analizará en busca de patrones.

El reconocimiento de características (o extracción de características) es el proceso de extraer las características relevantes de una imagen de entrada para que estas características puedan analizarse. Muchas imágenes contienen anotaciones o metadatos sobre la imagen que ayudan a la red a encontrar las características relevantes.

Cómo aprenden las redes neuronales a reconocer imágenes: introducción a las redes neuronales convolucionales

Obtener una intuición de cómo una red neuronal reconoce imágenes lo ayudará cuando esté implementando un modelo de red neuronal, así que exploremos brevemente el proceso de reconocimiento de imágenes en las próximas secciones.

Esta sección está destinada a servir como un curso acelerado/información básica sobre las redes neuronales convolucionales, así como un repaso para quienes estén familiarizados con ellas.

Extracción de características con filtros


[Crédito: commons.wikimedia.org]{.pequeño}

La primera capa de una red neuronal toma todos los píxeles dentro de una imagen. Una vez que todos los datos se han introducido en la red, se aplican diferentes filtros a la imagen, lo que forma representaciones de diferentes partes de la imagen. Esta es la extracción de características y crea "mapas de características".

Este proceso de extracción de características de una imagen se logra con una "capa convolucional", y la convolución simplemente forma una representación de parte de una imagen. Es a partir de este concepto de convolución que obtenemos el término Red neuronal convolucional (CNN), el tipo de red neuronal más utilizada en la clasificación/reconocimiento de imágenes. Recientemente, Transformers también ha realizado maravillas en la clasificación de imágenes, que se basan en la arquitectura de Recurrent Neural Network (RNN).

Si desea visualizar cómo funciona la creación de mapas de características para redes convolucionales, piense en encender una linterna sobre una imagen en una habitación oscura. A medida que desliza el haz sobre la imagen, está aprendiendo acerca de las características de la imagen. Un filtro es lo que usa la red para formar una representación de la imagen, y en esta metáfora, la luz de la linterna es el filtro.

El ancho del haz de tu linterna controla la cantidad de imagen que examinas a la vez, y las redes neuronales tienen un parámetro similar, el tamaño del filtro. El tamaño del filtro afecta la cantidad de imagen, la cantidad de píxeles que se examinan a la vez. Un tamaño de filtro común utilizado en las CNN es 3, y cubre tanto la altura como el ancho, por lo que el filtro examina un área de píxeles de 3 x 3.


[Crédito: commons.wikimedia.org]{.pequeño}

Mientras que el tamaño del filtro cubre el alto y el ancho del filtro, también se debe especificar la profundidad del filtro.

¿Cómo tiene profundidad una imagen 2D?

Las imágenes digitales se representan como alto, ancho y algún valor RGB que define los colores del píxel, por lo que la "profundidad" que se rastrea es la cantidad de canales de color que tiene la imagen. Las imágenes en escala de grises (sin color) solo tienen 1 canal de color, mientras que las imágenes en color tienen 3 canales de profundidad.

Todo esto significa que para un filtro de tamaño 3 aplicado a una imagen a todo color, las dimensiones de ese filtro serán 3 x 3 x 3. Por cada píxel cubierto por ese filtro, la red multiplica los valores del filtro con los valores en los píxeles mismos para obtener una representación numérica de ese píxel. Luego, este proceso se realiza para toda la imagen para lograr una representación completa. El filtro se mueve por el resto de la imagen de acuerdo con un parámetro llamado "zancada", que define cuántos píxeles se moverá el filtro después de calcular el valor en su posición actual. Un tamaño de zancada convencional para una CNN es 2.

El resultado final de todo este cálculo es un mapa de características. Este proceso generalmente se realiza con más de un filtro, lo que ayuda a preservar la complejidad de la imagen.

Funciones de activación {#funciones de activación}

Una vez que se ha creado el mapa de características de la imagen, los valores que representan la imagen se pasan a través de una función de activación o capa de activación. La función de activación toma valores que representan la imagen, que están en forma lineal (es decir, solo una lista de números) gracias a la capa convolucional, y aumenta su no linealidad ya que las imágenes en sí mismas no son lineales.

La función de activación típica que se usa para lograr esto es una Unidad Lineal Rectificada (ReLU), aunque hay algunas otras funciones de activación que se usan ocasionalmente (puede leer sobre ellas [aquí](https://keras.io/ activaciones/)).

Capas de agrupación

Una vez activados los datos, se envían a través de una capa de agrupación. Pooling "downsamples" una imagen, lo que significa que toma la información que representa la imagen y la comprime, haciéndola más pequeña. El proceso de agrupación hace que la red sea más flexible y más hábil para reconocer objetos/imágenes en función de las características relevantes.

Cuando miramos una imagen, normalmente no nos preocupamos por toda la información en el fondo de la imagen, solo por las características que nos interesan, como personas o animales.

De manera similar, una capa de agrupación en una CNN abstraerá las partes innecesarias de la imagen, conservando solo las partes de la imagen que considere relevantes, controladas por el tamaño especificado de la capa de agrupación.

Debido a que tiene que tomar decisiones sobre las partes más relevantes de la imagen, la esperanza es que la red aprenda solo las partes de la imagen que realmente representan el objeto en cuestión. Esto ayuda a prevenir el sobreajuste, donde la red aprende demasiado bien aspectos del caso de entrenamiento y no puede generalizar a nuevos datos.


[Crédito: Commons.wikimedia.org]{.pequeño}

Hay varias formas de agrupar valores, pero la agrupación máxima es la más utilizada. Max pooling obtiene el valor máximo de los píxeles dentro de un solo filtro (dentro de un solo punto en la imagen). Esto descarta 3/4 partes de la información, suponiendo que se utilicen filtros 2 x 2.

Los valores máximos de los píxeles se utilizan para tener en cuenta las posibles distorsiones de la imagen, y los parámetros/tamaño de la imagen se reducen para controlar el sobreajuste. Existen otros tipos de agrupación, como la agrupación promedio o la agrupación de suma, pero no se usan con tanta frecuencia porque la agrupación máxima tiende a producir una mayor precisión.

Aplanamiento

Las capas finales de nuestra CNN, las capas densamente conectadas, requieren que los datos estén en forma de vector para ser procesados. Por esta razón, los datos deben ser "aplanados". Los valores se comprimen en un vector largo o una columna de números ordenados secuencialmente.

Capa totalmente conectada

Las capas finales de la CNN son capas densamente conectadas o una red neuronal artificial (ANN). La función principal de ANN es analizar las características de entrada y combinarlas en diferentes atributos que ayudarán en la clasificación. Estas capas esencialmente forman colecciones de neuronas que representan diferentes partes del objeto en cuestión, y una colección de neuronas puede representar las orejas caídas de un perro o el enrojecimiento de una manzana. Cuando suficientes de estas neuronas se activan en respuesta a una imagen de entrada, la imagen se clasificará como un objeto.


[Crédito: Commons.wikimedia.org]{.pequeño}

La ANN calcula el error, o la diferencia entre los valores calculados y el valor esperado en el conjunto de entrenamiento. Luego, la red se somete a retropropagación, donde se calcula la influencia de una neurona dada en una neurona en la siguiente capa y se ajusta su influencia. Esto se hace para optimizar el rendimiento del modelo. Este proceso luego se repite una y otra vez. Así es como la red se entrena con los datos y aprende asociaciones entre las características de entrada y las clases de salida.

Las neuronas en las capas intermedias totalmente conectadas generarán valores binarios relacionados con las clases posibles. Si tiene cuatro clases diferentes (digamos un perro, un automóvil, una casa y una persona), la neurona tendrá un valor "1" para la clase que cree que representa la imagen y "0 " valor para las otras clases.

La capa final completamente conectada recibirá la salida de la capa anterior y entregará una probabilidad para cada una de las clases, sumando a uno. Si hay un valor de 0,75 en la categoría "perro", representa un 75 % de certeza de que la imagen es un perro.

El clasificador de imágenes ahora se ha entrenado y las imágenes se pueden pasar a la CNN, que ahora generará una suposición sobre el contenido de esa imagen.

El flujo de trabajo de aprendizaje automático

Antes de pasar a un ejemplo de entrenamiento de un clasificador de imágenes, tomemos un momento para comprender el flujo de trabajo o la canalización del aprendizaje automático. El proceso para entrenar un modelo de red neuronal es bastante estándar y se puede dividir en cuatro fases diferentes.

Preparación de datos {#preparación de datos}

Primero, deberá recopilar sus datos y ponerlos en un formulario en el que la red pueda capacitarse. Esto implica recopilar imágenes y etiquetarlas. Incluso si ha descargado un conjunto de datos que otra persona ha preparado, es probable que haya preprocesamiento o preparación que deba hacer antes de poder usarlo para capacitación. La preparación de datos es un arte en sí mismo, que implica lidiar con cosas como valores faltantes, datos dañados, datos en formato incorrecto, etiquetas incorrectas, etc.

En este artículo, utilizaremos un conjunto de datos preprocesados.

Creación del modelo

La creación del modelo de red neuronal implica tomar decisiones sobre varios parámetros e hiperparámetros. Debe tomar decisiones sobre la cantidad de capas que usará en su modelo, cuáles serán los tamaños de entrada y salida de las capas, qué tipo de funciones de activación usará, si usará o no abandono, etc.

Aprender qué parámetros e hiperparámetros usar vendrá con el tiempo (y mucho estudio), pero desde el principio hay algunas heurísticas que puede usar para ponerse en marcha y cubriremos algunas de ellas durante el ejemplo de implementación.

Entrenando al modelo {#entrenando al modelo}

Una vez que haya creado su modelo, simplemente cree una instancia del modelo y ajústela con sus datos de entrenamiento. La mayor consideración al entrenar un modelo es la cantidad de tiempo que el modelo tarda en entrenarse. Puede especificar la duración del entrenamiento para una red especificando el número de épocas para entrenar. Cuanto más entrene a un modelo, más mejorará su rendimiento, pero demasiadas épocas de entrenamiento corren el riesgo de sobreajustarse.

Elegir el número de épocas para entrenar es algo con lo que tendrá una idea, y es costumbre guardar los pesos de una red entre sesiones de entrenamiento para que no tenga que empezar de nuevo una vez que haya progresado en el entrenamiento de la red.

Evaluación del modelo

Hay varios pasos para evaluar el modelo. El primer paso para evaluar el modelo es comparar el rendimiento del modelo con un conjunto de datos de validación, un conjunto de datos que el modelo no ha sido entrenado. Comparará el rendimiento del modelo con este conjunto de validación y analizará su rendimiento a través de diferentes métricas.

Existen varias métricas para determinar el rendimiento de un modelo de red neuronal, pero la métrica más común es "accuracy", la cantidad de imágenes correctamente clasificadas dividida por el total número de imágenes en su conjunto de datos.

Una vez que haya visto la precisión del rendimiento del modelo en un conjunto de datos de validación, normalmente regresará y entrenará la red nuevamente utilizando parámetros ligeramente modificados, porque es poco probable que esté satisfecho con su red. s rendimiento la primera vez que entrenas. Seguirá ajustando los parámetros de su red, reentrenándola y midiendo su rendimiento hasta que esté satisfecho con la precisión de la red.

Finalmente, probará el rendimiento de la red en un conjunto de prueba. Este conjunto de prueba es otro conjunto de datos que su modelo nunca antes había visto.

Quizás te estés preguntando:

¿Por qué molestarse con el conjunto de pruebas? Si está obteniendo una idea de la precisión de su modelo, ¿no es ese el propósito del conjunto de validación?

Es una buena idea mantener un lote de datos que la red nunca ha visto para realizar pruebas porque todos los ajustes de los parámetros que realiza, combinados con la nueva prueba en el conjunto de validación, podrían significar que su red ha aprendido algunas idiosincrasias de la validación. conjunto que no se generalizará a datos fuera de la muestra.

Por lo tanto, el propósito del conjunto de prueba es verificar problemas como el sobreajuste y estar más seguro de que su modelo es realmente apto para funcionar en el mundo real.

Clasificación/reconocimiento de imágenes con una CNN en Keras

Hemos cubierto mucho hasta ahora, y si toda esta información ha sido un poco abrumadora, ver estos conceptos reunidos en un clasificador de muestra entrenado en un conjunto de datos debería hacer que estos conceptos sean más concretos. Entonces, veamos un ejemplo completo de reconocimiento de imágenes con Keras, desde la carga de los datos hasta la evaluación.


[Crédito: www.cs.toronto.edu]{.pequeño}

Para empezar, necesitaremos un conjunto de datos para entrenar. En este ejemplo, utilizaremos el famoso conjunto de datos CIFAR-10. CIFAR-10 es un gran conjunto de datos de imágenes que contiene más de 60 000 imágenes que representan 10 clases diferentes de objetos, como gatos, aviones y automóviles.

Las imágenes son RGB a todo color, pero son bastante pequeñas, solo 32 x 32. Una gran cosa sobre el conjunto de datos CIFAR-10 es que viene preempaquetado con Keras, por lo que es muy fácil cargar el conjunto de datos y las imágenes necesitan muy poco preprocesamiento.

Lo primero que debemos hacer es importar las bibliotecas necesarias. Mostraré cómo se usan estas importaciones a medida que avanzamos, pero por ahora sepa que usaremos entumecido, y varios módulos asociados a Keras:

1
2
3
4
import numpy
from tensorflow import keras
from keras.constraints import maxnorm
from keras.utils import np_utils

Vamos a usar una semilla aleatoria aquí para que usted pueda replicar los resultados logrados en este artículo, por lo que necesitamos numpy:

1
2
# Set random seed for purposes of reproducibility
seed = 21

Preparación de los datos

Necesitamos una importación más: el conjunto de datos.

1
from keras.datasets import cifar10

Ahora vamos a cargar el conjunto de datos. Podemos hacerlo simplemente especificando en qué variables queremos cargar los datos y luego usando la función load_data():

1
2
# Loading in the data
(X_train, y_train), (X_test, y_test) = cifar10.load_data()

En la mayoría de los casos, deberá realizar un preprocesamiento de sus datos para que estén listos para su uso, pero dado que estamos utilizando un conjunto de datos preempaquetado, es necesario realizar muy poco preprocesamiento. Una cosa que queremos hacer es normalizar los datos de entrada.

Si los valores de los datos de entrada están en un rango demasiado amplio, puede afectar negativamente el rendimiento de la red. En este caso, los valores de entrada son los píxeles de la imagen, que tienen un valor entre 0 y 255.

Entonces, para normalizar los datos, simplemente podemos dividir los valores de la imagen por 255. Para hacer esto, primero debemos hacer que los datos sean de tipo flotante, ya que actualmente son números enteros. Podemos hacer esto usando el comando Numpy astype() y luego declarando qué tipo de datos queremos:

1
2
3
4
5
# Normalize the inputs from 0-255 to between 0 and 1 by dividing by 255
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
X_train = X_train / 255.0
X_test = X_test / 255.0

Otra cosa que tendremos que hacer para preparar los datos para la red es codificación one-hot los valores. No entraré en los detalles de la codificación one-hot aquí, pero por ahora sepa que la red no puede usar las imágenes tal como están, deben codificarse primero y es mejor usar la codificación one-hot al hacer la clasificación binaria.

Efectivamente, estamos haciendo una clasificación binaria aquí porque una imagen pertenece a una clase o no, no puede estar en algún punto intermedio. El comando Numpy to_categorical() se usa para codificar en caliente. Es por eso que importamos la función np_utils de Keras, ya que contiene to_categorical().

También necesitamos especificar la cantidad de clases que hay en el conjunto de datos, para saber cuántas neuronas comprimir la capa final hasta:

1
2
3
4
# One-hot encode outputs
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
class_num = y_test.shape[1]

Diseño del modelo

Hemos llegado a la etapa en la que diseñamos el modelo CNN. Lo primero que debemos hacer es definir el formato que nos gustaría usar para el modelo, Keras tiene varios formatos o blueprints diferentes para construir modelos, pero Sequential es el más utilizado, y por esa razón, lo hemos importado de Keras.

Crear el modelo

Podemos construir el modelo secuencial creando una instancia en blanco y luego agregándole capas:

1
2
3
4
model = Sequential()
model.add(keras.layers.layer1)
model.add(keras.layers.layer2)
model.add(keras.layers.layer3)

O, podemos pasar cada capa como un elemento en una lista en la llamada al constructor Sequential():

1
2
3
4
5
model = keras.Sequential([
    keras.layers.layer1,
    keras.layers.layer2,
    keras.layers.layer3    
])

La primera capa de nuestro modelo es una capa convolucional. Tomará las entradas y ejecutará filtros convolucionales sobre ellas.

Al implementar estos en Keras, tenemos que especificar el número de canales/filtros que queremos (esos son los 32 a continuación), el tamaño del filtro que queremos (3 x 3 en este caso), la forma de entrada (al crear la primera capa) y la activación y relleno que necesitamos. Todos estos son hiperparámetros en la CNN que son propensos a sintonizar. Como se mencionó, relu es la activación más común, y padding='same' solo significa que no estamos cambiando el tamaño de la imagen en absoluto. También puede probar otras capas de activación, aunque relu es un valor predeterminado muy sensato para probar primero antes de ajustar:

1
2
3
model = keras.Sequential()
model.add(keras.layers.Conv2D(32, (3, 3), input_shape=X_train.shape[1:], padding='same'))
model.add(keras.layers.Activation('relu'))

{.icon aria-hidden=“true”}

Nota: Dado que una capa de activación está presente después de prácticamente todas las capas, puede agregarla como un argumento de cadena a la capa anterior. Keras agregará automáticamente una capa de activación y este enfoque suele ser mucho más legible.

1
model.add(keras.layers.Conv2D(32, 3, input_shape=(32, 32, 3), activation='relu', padding='same'))

Ahora agregaremos una capa de abandono para evitar el sobreajuste, que funciona al eliminar aleatoriamente algunas de las conexiones entre las capas (0.2 significa que elimina el 20% de las conexiones existentes):

1
model.add(keras.layers.Dropout(0.2))

También es posible que deseemos agregar la normalización por lotes aquí. Normalización por lotes normaliza las entradas que se dirigen a la siguiente capa, asegurando que la red siempre cree activaciones con la misma distribución que deseamos:

1
model.add(keras.layers.BatchNormalization())

Este es el bloque básico utilizado para construir CNN. Capa convolucional, activación, dropout, pooling. Estos bloques se pueden apilar, normalmente en un patrón piramidal en términos de complejidad. El siguiente bloque generalmente contiene una capa convolucional con un filtro más grande, lo que le permite encontrar patrones con mayor detalle y abstraer aún más, seguido de una capa de agrupación, abandono y normalización por lotes:

1
2
3
4
model.add(keras.layers.Conv2D(64, 3, activation='relu', padding='same'))
model.add(keras.layers.MaxPooling2D(2))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.BatchNormalization())

Puede variar el número exacto de capas convolucionales que tiene a su gusto, aunque cada una agrega más gastos de cómputo. Tenga en cuenta que, a medida que agrega capas convolucionales, normalmente aumenta la cantidad de filtros para que el modelo pueda aprender representaciones más complejas. Si los números elegidos para estas capas parecen algo arbitrarios, en general, aumenta los filtros a medida que avanza y se recomienda hacerlos potencias de 2, lo que puede otorgar un ligero beneficio cuando se entrena en una GPU.

Es importante no tener demasiadas capas de agrupación, ya que cada agrupación descarta algunos datos al reducir las dimensiones de la entrada con un factor dado. En nuestro caso, corta las imágenes por la mitad. La agrupación con demasiada frecuencia hará que las capas densamente conectadas no tengan casi nada que aprender cuando los datos les lleguen.

La cantidad exacta de capas de agrupación que debe usar variará según la tarea que esté realizando, y es algo que se familiarizará con el tiempo. Dado que las imágenes son tan pequeñas aquí, no agruparemos más de dos veces.

Ahora puede repetir estas capas para darle a su red más representaciones para trabajar:

1
2
3
4
5
6
7
8
model.add(keras.layers.Conv2D(64, 3, activation='relu', padding='same'))
model.add(keras.layers.MaxPooling2D(2))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.BatchNormalization())
    
model.add(keras.layers.Conv2D(128, 3, activation='relu', padding='same'))
model.add(keras.layers.Dropout(0.2))
model.add(keras.layers.BatchNormalization())

Una vez que hayamos terminado con las capas convolucionales, necesitamos ‘Aplanar’ los datos, razón por la cual importamos la función anterior. También agregaremos una capa de abandono nuevamente:

1
2
model.add(keras.layers.Flatten())
model.add(keras.layers.Dropout(0.2))

Ahora hacemos uso de la importación Dense y creamos la primera capa densamente conectada. Necesitamos especificar el número de neuronas en la capa densa. Tenga en cuenta que la cantidad de neuronas en las capas sucesivas disminuye, acercándose finalmente a la misma cantidad de neuronas que clases en el conjunto de datos (en este caso, 10).

Podemos tener múltiples capas densas aquí, y estas capas extraen información de los mapas de características para aprender a clasificar imágenes según los mapas de características. Dado que tenemos imágenes bastante pequeñas condensadas en mapas de características bastante pequeños, no es necesario tener varias capas densas. Una sola capa simple de 32 neuronas debería ser suficiente:

1
2
3
model.add(keras.layers.Dense(32, activation='relu'))
model.add(keras.layers.Dropout(0.3))
model.add(keras.layers.BatchNormalization())

{.icon aria-hidden=“true”}

Nota: Cuidado con las capas densas. Dado que están completamente conectados, tener solo un par de capas aquí en lugar de una sola aumenta significativamente la cantidad de parámetros que se pueden aprender. Por ejemplo, si tuviéramos tres capas densas (128, 64 y 32), la cantidad de parámetros entrenables se dispararía a 2,3 millones, a diferencia de los 400k de este modelo. El modelo más grande en realidad incluso tenía una menor precisión, además de los tiempos de entrenamiento más largos en nuestras pruebas.

En la capa final, pasamos el número de clases por el número de neuronas. Cada neurona representa una clase, y la salida de esta capa será un vector de 10 neuronas con cada neurona almacenando alguna probabilidad de que la imagen en cuestión pertenezca a la clase que representa.

Finalmente, la función de activación softmax selecciona como salida la neurona con mayor probabilidad, votando que la imagen pertenece a esa clase:

1
model.add(keras.layers.Dense(class_num, activation='softmax'))

Ahora que hemos diseñado el modelo que queremos usar, solo tenemos que compilarlo. El optimizador es lo que ajustará los pesos en su red para acercarse al punto de menor pérdida. El algoritmo Estimación de momento adaptativo (Adam) es un optimizador de uso muy común y un optimizador predeterminado muy sensato para probar. Por lo general, es estable y funciona bien en una amplia variedad de tareas, por lo que es probable que funcione bien aquí.

Si no es así, podemos cambiar a un optimizador diferente, como Nadam (Adam acelerado por Nesterov), RMSProp (usado a menudo para regresión), etc.

Realizaremos un seguimiento de la precisión y la precisión de validación para asegurarnos de evitar sobreajustar mal la CNN. Si los dos comienzan a divergir significativamente y la red funciona mucho mejor en el conjunto de validación, se está sobreajustando.

1
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy', 'val_accuracy'])

Podemos imprimir el resumen del modelo para ver cómo se ve todo el modelo.

1
print(model.summary())

Imprimir el resumen nos dará bastante información y puede usarse para cotejar su propia arquitectura con la que se presenta en la guía:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_43 (Conv2D)           (None, 32, 32, 32)        896       
_________________________________________________________________
dropout_50 (Dropout)         (None, 32, 32, 32)        0         
_________________________________________________________________
batch_normalization_44 (Batc (None, 32, 32, 32)        128       
_________________________________________________________________
conv2d_44 (Conv2D)           (None, 32, 32, 64)        18496     
_________________________________________________________________
max_pooling2d_20 (MaxPooling (None, 16, 16, 64)        0         
_________________________________________________________________
dropout_51 (Dropout)         (None, 16, 16, 64)        0         
_________________________________________________________________
batch_normalization_45 (Batc (None, 16, 16, 64)        256       
_________________________________________________________________
conv2d_45 (Conv2D)           (None, 16, 16, 64)        36928     
_________________________________________________________________
max_pooling2d_21 (MaxPooling (None, 8, 8, 64)          0         
_________________________________________________________________
dropout_52 (Dropout)         (None, 8, 8, 64)          0         
_________________________________________________________________
batch_normalization_46 (Batc (None, 8, 8, 64)          256       
_________________________________________________________________
conv2d_46 (Conv2D)           (None, 8, 8, 128)         73856     
_________________________________________________________________
dropout_53 (Dropout)         (None, 8, 8, 128)         0         
_________________________________________________________________
batch_normalization_47 (Batc (None, 8, 8, 128)         512       
_________________________________________________________________
flatten_6 (Flatten)          (None, 8192)              0         
_________________________________________________________________
dropout_54 (Dropout)         (None, 8192)              0         
_________________________________________________________________
dense_18 (Dense)             (None, 32)                262176    
_________________________________________________________________
dropout_55 (Dropout)         (None, 32)                0         
_________________________________________________________________
batch_normalization_48 (Batc (None, 32)                128       
_________________________________________________________________
dense_19 (Dense)             (None, 10)                330       
=================================================================
Total params: 393,962
Trainable params: 393,322
Non-trainable params: 640

Ahora vamos a entrenar el modelo. Para hacer esto, todo lo que tenemos que hacer es llamar a la función fit() en el modelo y pasar los parámetros elegidos. Además, también podemos guardar su historial y trazar su rendimiento durante el proceso de entrenamiento. Esto a menudo nos brinda información valiosa sobre el progreso que ha logrado la red, y si podríamos haberla entrenado más y si comenzará a sobreajustarse si lo hacemos.

Hemos usado una semilla para la reproducibilidad, así que entrenemos la red y guardemos su rendimiento:

1
2
numpy.random.seed(seed)
history = model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=25, batch_size=64)

Esto resulta en:

1
2
3
4
5
Epoch 1/25
782/782 [==============================] - 12s 15ms/step - loss: 1.4851 - accuracy: 0.4721 - val_loss: 1.1805 - val_accuracy: 0.5777
...
Epoch 25/25
782/782 [==============================] - 11s 14ms/step - loss: 0.4154 - accuracy: 0.8538 - val_loss: 0.5284 - val_accuracy: 0.8197

Tenga en cuenta que, en la mayoría de los casos, le gustaría tener un conjunto de validación que sea diferente del conjunto de prueba, por lo que especificaría un porcentaje de los datos de entrenamiento para usar como conjunto de validación. En este caso, solo pasaremos los datos de prueba para asegurarnos de que los datos de prueba se reserven y no se entrenen. Solo tendremos datos de prueba en este ejemplo, para simplificar las cosas.

Ahora podemos evaluar el modelo y ver cómo se desempeñó. Simplemente llame a model.evaluate():

1
2
3
# Model evaluation
scores = model.evaluate(X_test, y_test, verbose=0)
print("Accuracy: %.2f%%" % (scores[1]*100))

Y somos recibidos con el resultado:

1
Accuracy: 82.01%

With Transfer Learning and more powerful architectures, you can achieve much more. We showcase a 94% accuracy in our Guide to Clasificación de imágenes con aprendizaje por transferencia en Keras - Cree modelos CNN de última generación!

Adicionalmente, podemos visualizar el historial muy fácilmente:

1
2
3
4
5
import pandas as pd
import matplotlib.pyplot as plt

pd.DataFrame(history.history).plot()
plt.show()

Esto resulta en:

learning curves

A partir de las curvas, podemos ver que el entrenamiento en realidad no se detuvo después de 25 épocas; probablemente podría haber durado más que eso en este mismo modelo y arquitectura, lo que habría producido una mayor precisión.

¡Y eso es! Ahora tenemos una CNN de reconocimiento de imágenes entrenada. No está mal para la primera ejecución, pero probablemente querrá jugar con la estructura y los parámetros del modelo para ver si puede obtener un mejor rendimiento.

Yendo más lejos: proyecto de extremo a extremo portátil

¿Tu naturaleza inquisitiva te hace querer ir más allá? Recomendamos consultar nuestro Proyecto guiado: ["Construyendo su primera CNN con Keras"](https://wikihtp.com/courses/building-your-first-convolutional-neural-network -con-keras/){target="_blank"}.

[](https://wikihtp.com/courses/building-your-first-convolutional-neuronal- red-con-keras)

¿Por qué se predijo una clase? ¿Dónde se equivocó el modelo? ¿Qué hizo que predijera mal? ¿En qué estaba la atención de la modelo? ¿Cómo son las características aprendidas? ¿Podemos separarlos en clases distintas? ¿Qué tan cerca están las características que hacen la Clase N de la característica que hace la Clase M?

Aquí está el espacio de características latentes de su modelo visualizado y, de lo contrario, oculto para usted:

La literatura es vasta, y es demasiado larga y teórica o demasiado breve para ser práctica. En este proyecto guiado, pasaremos por el proceso de creación de su propia CNN con Keras, suponiendo que esté familiarizado con los fundamentos.

En este proyecto, a través de un enfoque práctico y portátil, aprenderá sobre:

  • Co-ocurrencia y la fuente del sesgo de co-ocurrencia en conjuntos de datos
  • Búsqueda, descarga de conjuntos de datos y extracción de datos.
  • Visualización de subconjuntos de imágenes.
  • Carga y preprocesamiento de datos
  • Promesas y peligros del aumento de datos y la clase ImageDataGenerator de Keras
  • Definición de una arquitectura CNN personalizada
  • Implementando LRFinder con Keras y encontrando tasas de aprendizaje automáticamente
  • Evaluar las habilidades de clasificación de un modelo.
  • Interpretar las predicciones de un modelo y evaluar errores
  • Qué hace que la red prediga mal
  • Interpretar los mapas de atención de un modelo para identificar qué modelos realmente aprenden con tf-keras-vis y GradCam++
  • Interpretar lo que han aprendido las capas convolucionales del modelo a través del Análisis de Componentes Principales y t-SNE
  • Cómo los motores de búsqueda de similitud encuentran imágenes similares

Conclusión

Ahora que ha implementado su primera red de reconocimiento de imágenes en Keras, sería una buena idea jugar con el modelo y ver cómo el cambio de sus parámetros afecta su rendimiento.

Esto le dará cierta intuición sobre las mejores opciones para los diferentes parámetros del modelo. También debe leer sobre las diferentes opciones de parámetros e hiperparámetros mientras lo hace. Una vez que se sienta cómodo con estos, puede intentar implementar su propio clasificador de imágenes en un conjunto de datos diferente.