Blog
Proyecto: Reconocimiento de Objetos de en Fotografías con CIFAR-10
- Publicado por: Rafael Fernandez
- Categoría: Natural Language Processing
En esta lección descubrirá cómo desarrollar y evaluar modelos de aprendizaje profundo para el reconocimiento de objetos en Keras.
-Acerca del conjunto de datos de reconocimiento de objetos CIFAR-10 y cómo cargarlo y utilizarlo en Keras.
-Cómo crear una Red Neural Convolucional simple para el reconocimiento de objetos.
-Cómo elevar el rendimiento mediante la creación de redes neuronales convolucionales más profundas.
Un problema difícil en el que las redes neuronales tradicionales pueden no funcionar es cuando tenemos que reconocer objetos. Es donde un modelo es capaz de identificar objetos en imágenes.
Es posible que desee acelerar el cálculo de este tutorial utilizando la GPU en lugar del hardware de la CPU. Se trata de una sugerencia, no de un requisito. El tutorial funcionará en la CPU.
Conjunto de datos de reconocimiento de objetos fotográficos
El problema de la identificación automática de objetos en las fotografías es dificil debido al número casi infinito de permutaciones de objetos, posiciones, iluminación, etc. Este es un problema bien estudiado en la visión por computador y, más recientemente, una importante demostración de la capacidad de aprendizaje profundo. El Instituto Canadiense de Investigaciones Avanzadas elaboró un conjunto de datos estándar sobre visión por computador y aprendizaje profundo para este problema. (CIFAR).
El conjunto de datos CIFAR-10 consta de 60.000 fotos divididas en 10 clases (de ahí el nombre CIFAR-10)1. Las clases incluyen objetos comunes como aviones, automóviles, aves, gatos, etc. en. El conjunto de datos se divide de forma estándar, donde se utilizan 50.000 imágenes para la formación de un modelo y los 10.000 restantes para evaluar su desempeño. Las imágenes están en los 3 canales (rojo, verde y azul) y son cuadrados pequeños que miden 32 x 32 píxeles.
Cargar el conjunto de datos CIFAR-10 en Keras
El conjunto de datos CIFAR-10 se puede cargar fácilmente en Keras. Keras tiene la facilidad de descargar automáticamente conjuntos de datos estándar como CIFAR-10 y almacenarlos en el directorio ~/.keras/datasets usando la función cifar10.load data(). Este conjunto de datos tiene 163 MB su descarga son munitos o segundos dependiendo de tu conexión. Una vez descargado, las llamadas subsiguientes a la función se cargarán en el conjunto de datos listo para su uso.
El conjunto de datos se almacena en Python listo para su uso en Keras. Cada imagen se representa como una matriz tridimensional, con dimensiones para rojo, verde, azul, ancho y altura. Podemos graficar imágenes directamente usando la librería de Matplotlib Python.
# graficar ad hoc CIFAR10 from keras.datasets import cifar10 from matplotlib import pyplot # cargamos los datos (X_train, y_train), (X_test, y_test) = cifar10.load_data() # creamos una malla de 3 x 3 imagenes for i in range(0, 219): pyplot.subplot(330 + 1 + i) pyplot.imshow(X_train[i*8]) # show the plot pyplot.show()
Ejecutando el código, creamos unas fotografías de 3 x 3. Las imágenes se han ampliado a partir de su pequeño tamaño de 32 x 32, pero se pueden ver claramente algunos animales y automóviles. También puede ver cierta distorsión en las imágenes que se han forzado a la relación de aspecto cuadrado.
Simple Red Neuronal Convolucional (CNN) para CIFAR-10
Con CIFAR-10 podemos resolver una gran cantidad de problemas utilizando una red neuronal convolucional (CNN). Podemos empezar rápidamente importando todas las clases y funciones que necesitaremos en este ejemplo.
# Simple CNN modelo para  CIFAR-10 import numpy from keras.datasets import cifar10 from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.constraints import maxnorm from keras.optimizers import SGD from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.utils import np_utils from keras import backend as K K.set_image_dim_ordering('th')
Como es buena práctica, a continuación inicializamos la semilla del número aleatorio con una constante para asegurarnos de que los resultados son reproducibles.
# generador de números aleatorios seed=7 numpy.random.seed(seed)
A continuación podemos cargar el conjunto de datos CIFAR-10.
# load data (X_train, y_train), (X_test, y_test) = cifar10.load_data()
Los valores de los píxeles están en el rango de 0 a 255 para cada uno de los canales rojo, verde y azul. Es una buena práctica trabajar con datos normalizados. Debido a que los valores de entrada son bien conocidos, podemos fácilmente normalizar al rango de 0 a 1 dividiendo cada valor por la observación máxima que es 255.
Los datos se cargan como enteros, por lo que debemos lanzarlos a valores de coma flotante para poder realizar la división.
X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train = X_train / 255.0 X_test = X_test / 255.0
Las variables de salida se denotan como un vector de números enteros de 0 a 1 para cada clase. Podemos usar una codificación en caliente para transformarlos en una matriz binaria con el fin de modelar mejor el problema de la clasificación. Sabemos que hay 10 clases para este problema, así que podemos esperar que la matriz binaria tenga un ancho de 10.
# codificacion en caliente de la salida y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) num_classes = y_test.shape[1]
Comencemos definiendo una estructura simple de CNN como línea de base y evaluemos como funciona. Utilizaremos una estructura con dos capas convolucionales seguidas una capa pool y una red a capas completamente conectadas para hacer predicciones. Nuestra estructura básica de red puede resumirse de la siguiente manera:
- Capa de entrada convolucional, 32 mapas de características con un tamaño de 3 x 3, una activación de rectier y una restricción de peso de la norma máxima establecida en 3.
- Abandono fijado en el 20%.
- Capa convolucional, 32 mapas de características con un tamaño de 3 x 3, una función de activación de rectier y una restricción de peso de la norma máxima establecida en 3.
- Capa máxima de pool con el tamaño 2 x 2.
- Capa Flatten.
- Capa totalmente conectada con 512 unidades y función de activación de rectier.
21.3. CNN simple para CIFAR-10 152. - Abandono al 50%.
- Capa de salida totalmente conectada con 10 unidades y función de activación softmax.
Se utiliza una función de pérdida logarítmica con el algoritmo de optimización de descenso de gradiente estocástico configurado con un gran impulso y disminución de peso, comenzando con una tasa de aprendizaje de 0,01. A continuación se proporciona una visualización de la estructura de la red.
Capa de salida (10 salidas)
^
|
Abandono del 20%
^
|
Capa oculta 512 neuronas
^
|
Capa pool 2 x2
^
|
Capa convolucional 32 mapas 3 x 3
^
|
Abandono del 20%
^
|
Capa convolucional 32 mapas 3 x 3
^
|
Capa visible 3 x 32 x 32
# Creacion del modelo model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=(3, 32, 32), padding='same', activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.2)) model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_constraint=maxnorm(3))) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) # Compilacion del modelo epochs = 25 lrate = 0.01 decay = lrate/epochs sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False) model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) print(model.summary())
Ajustamos este modelo con 25 épocas y un tamaño de lote de 32. Se eligió un pequeño número de épocas para hacer este tutorial de forma rápida. Normalmente, el número de épocas sería uno o dos órdenes de magnitud mayor para este problema. Una vez que el modelo se ajusta, lo evaluamos en el conjunto de datos de prueba e imprimimos la precisión de la clasificación.
# Ajustamos el modelo model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=32) # Final evaluacion del modelo scores = model.evaluate(X_test, y_test, verbose=0) print("Accuracy: %.2f%%" % (scores[1]*100))
Código completo
# Simple modelo CNN para el conjunto de datos de CIFAR-10 import numpy from keras.datasets import cifar10 from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.constraints import maxnorm from keras.optimizers import SGD from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.utils import np_utils from keras import backend as K K.set_image_dim_ordering('th') # semilla aleatoria seed = 7 numpy.random.seed(seed) # cargamos los datos (X_train, y_train), (X_test, y_test) = cifar10.load_data() # normalize inputs from 0-255 to 0.0-1.0 X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train = X_train / 255.0 X_test = X_test / 255.0 # codificacion en caliente de salida y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) num_classes = y_test.shape[1] # Creacion del modelo model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=(3, 32, 32), padding='same', activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.2)) model.add(Conv2D(32, (3, 3), activation='relu', padding='same', kernel_constraint=maxnorm(3))) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dense(512, activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.5)) model.add(Dense(num_classes, activation='softmax')) # Compilamos el modelo epochs = 25 lrate = 0.01 decay = lrate/epochs sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False) model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) print(model.summary()) # Ajustamos el modelo model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=32) # Final evaluacion del modelo scores = model.evaluate(X_test, y_test, verbose=0) print("Precision: %.2f%%" % (scores[1]*100))
La precisión y la pérdida de clasificación se imprimen en cada época en los conjuntos de datos de entrenamiento y prueba. El modelo se evalúa en el conjunto de prueba y logra una precisión de 70.85%, que es bueno pero no excelente.
Epoch 23/25 50000/50000 [==============================] - 143s - loss: 0.2399 - acc: 0.9168 - val_loss: 1.0680 - val_acc: 0.7077 Epoch 24/25 50000/50000 [==============================] - 143s - loss: 0.2285 - acc: 0.9197 - val_loss: 1.0702 - val_acc: 0.7119 Epoch 25/25 50000/50000 [==============================] - 143s - loss: 0.2177 - acc: 0.9238 - val_loss: 1.0686 - val_acc: 0.7085 Presicion: 70.85%
Podemos mejorar la precisión significativamente al crear una red mucho más profunda. Esto es lo que veremos en el siguiente punto.
Red Neuronal Convolucional (CNN) más grande para CIFAR-10
Hemos visto que una simple CNN funciona mal en este complejo problema. En esta sección examinamos la posibilidad de ampliar el tamaño y la complejidad de nuestro modelo. Vamos a diseñar una versión profunda de la Red Neuronal Convolucional (CNN) simple de arriba. Podemos introducir una ronda adicional de circunvoluciones con muchas más mapas de características. Usaremos el mismo patrón de convolucional, abandono, convolucional y las capas de pooling.
Este patrón se repetirá 3 veces con 32, 64 y 128 mapas de características. El efecto será un número creciente de mapas de características con un tamaño cada vez menor dado el máximo pooling de capas. Por último, una capa densa adicional y más grande se utilizará en el extremo de salida en un intento de traducir mejor el gran número de mapas de características a los valores de la clase. Podemos resumir la nueva arquitectura de red de la siguiente manera:
1. Capa de entrada convolucional, 32 mapas de características con un tamaño de 3 x 3 y una activación de rectier.
2. Abandono al 20%.
3. Capa convolucional, 32 mapas de características con un tamaño de 3 x 3 y una función de activación de rectier.
4. Capa máxima de pooling con el tamaño 2 x 2.
5. Capa convolucional, 64 mapas de características con un tamaño de 3 x 3 y una función de activación de rectier.
6. Abandono al 20%.
7. Capa convolucional, 64 mapas de características con un tamaño de 3 x 3 y una función de activación de rectier.
8. Capa máxima de pooling con el tamaño 2 x 2.
9. Capa convolucional, 128 mapas de características con un tamaño de 3 x 3 y una función de activación de rectier.
10. Abandono al 20%.
11. Capa convolucional, 128 mapas de características con un tamaño de 3 x 3 y una función de activación de rectier.
12. Capa máxima de pooling con el tamaño 2 x 2.
13. Capa flatten.
14. Abandono al 20%.
15. Capa totalmente conectada con 1.024 unidades y función de activación de rectier.
16. Abandono al 20%.
17. Capa totalmente conectada con 512 unidades y función de activación de rectier.
18. Abandono al 20%.
19. Capa de salida totalmente conectada con 10 unidades y función de activación softmax.
Esta es una red más grande y un poco difícil de visualizar. Podemos evaluar este modelo usando el mismo procedimiento anterior y el mismo número de épocas pero con un tamaño de lote mayor de 64.
# Red neuronal convolucional grande para CIFAR-10 Dataset import numpy from keras.datasets import cifar10 from keras.models import Sequential from keras.layers import Dense from keras.layers import Dropout from keras.layers import Flatten from keras.constraints import maxnorm from keras.optimizers import SGD from keras.layers.convolutional import Conv2D from keras.layers.convolutional import MaxPooling2D from keras.utils import np_utils from keras import backend as K K.set_image_dim_ordering('th') # semilla aleatoria para reproducibilidad seed = 7 numpy.random.seed(seed) # cargamos los datos (X_train, y_train), (X_test, y_test) = cifar10.load_data() # normalizamos las entradas 0-255 para 0.0-1.0 X_train = X_train.astype('float32') X_test = X_test.astype('float32') X_train = X_train / 255.0 X_test = X_test / 255.0 # una codificacion en caliente a la salida y_train = np_utils.to_categorical(y_train) y_test = np_utils.to_categorical(y_test) num_classes = y_test.shape[1] # Creacion del modelo model = Sequential() model.add(Conv2D(32, (3, 3), input_shape=(3, 32, 32), activation='relu', padding='same')) model.add(Dropout(0.2)) model.add(Conv2D(32, (3, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(64, (3, 3), activation='relu', padding='same')) model.add(Dropout(0.2)) model.add(Conv2D(64, (3, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, (3, 3), activation='relu', padding='same')) model.add(Dropout(0.2)) model.add(Conv2D(128, (3, 3), activation='relu', padding='same')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Flatten()) model.add(Dropout(0.2)) model.add(Dense(1024, activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu', kernel_constraint=maxnorm(3))) model.add(Dropout(0.2)) model.add(Dense(num_classes, activation='softmax')) # Compilamos el modelo epochs = 25 lrate = 0.01 decay = lrate/epochs sgd = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False) model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) print(model.summary()) # Ajustamos el modelo model.fit(X_train, y_train, validation_data=(X_test, y_test), epochs=epochs, batch_size=64) # Final evaluacion del model scores = model.evaluate(X_test, y_test, verbose=0) print("Precision: %.2f%%" % (scores[1]*100))
Al ejecutar este ejemplo, se imprime la precisión y la pérdida de la clasificación en los conjuntos de datos de formación y de pruebas de cada época. La estimación de la precisión de la clasificación para el modelo es de 78.77%, lo cual es casi 10 puntos mejor que nuestro modelo más simple.
Consejos para mejorar el rendimiento del modelo
Hemos logrado buenos resultados en este problema tan difícil, pero aún estamos a un buen paso de lograr resultados muy buenos. A continuación se presentan algunas ideas que usted puede tratar de extender sobre el modelo y mejorar el rendimiento del modelo.
- Entrena para más épocas. Cada modelo fue entrenado para un número muy pequeño de épocas, 25. Es común entrenar grandes redes neuronales convolucionales para cientos o miles de épocas. Yo esperaría que las mejoras en el rendimiento puedan lograrse aumentando de manera significativa el número de épocas de entrenamiento.
- Aumento de datos de imagen. Los objetos de la imagen varían en su posición. Otra mejora es probable que se pueda lograr con un aumento en el rendimiento del modelo mediante el uso de algún tipo de aumento de datos. Métodos como la estandarización y los desplazamientos aleatorios de la imagen pueden ser beneficiosos.
- Topología de red más profunda. La red más grande que se presenta es profunda, pero incluso redes mas profundas se podrían diseñar para el problema. Esto puede implicar más mapas de características y quizás un pooling menos agresivo. Además, las topologías de red convolucional estándar que han demostrado ser útiles pueden ser adoptadas y evaluadas sobre este problema.
➡ Aprende mucho mas con nuestro curso de Deep Learning: