Alberto Beiz

Mis pruebas y experimentos.

Contacta sin miedo:

Preparando un dataset de imágenes para utilizarlo en Keras

La idea es ver como preparar un dataset de imágenes cualquiera para que sea compatible con nuestros modelos de Keras.

Voy a descargarme las imágenes de la competición de Kaggle de diferenciar entre imágenes de perros y de gatos. Kaggle es una comunidad de usuarios interesados en machine learning, organizan competiciones con premios en metálico y comparten muchos datasets completamente gratis. Hay que registrarse y aceptar las normas de la competición antes de poder descargar las imágenes.

from glob import glob
import numpy as np
import os

working_dir = os.getcwd()
LESSON_HOME_DIR = working_dir + '/catsdogs'
DATA_HOME_DIR = LESSON_HOME_DIR + '/data'
# Instalamos la herramienta de kaggle
! pip install kaggle-cli
# Creamos la carpeta
% mkdir $LESSON_HOME_DIR
% cd $LESSON_HOME_DIR
/home/nbuser/catsdogs
# Descargamos los archivos
! kg config -g -u <user> -p <password> -c dogs-vs-cats-redux-kernels-edition
! kg download
downloading https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/download/test.zip

test.zip 100% |#####################################| Time: 0:00:11  23.7 MiB/s

downloading https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/download/train.zip

train.zip 100% |####################################| Time: 0:00:23  22.7 MiB/s

downloading https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/download/sample_submission.csv

sample_submission.csv 100% |########################| Time: 0:00:00 306.8 KiB/s
# Comprobamos
% ls
sample_submission.csv  test.zip  train.zip
# Descomprimimos el set de entrenamiento.
# Ten paciencia
import zipfile

zip = zipfile.ZipFile('train.zip')
zip.extractall('data')

% rm train.zip
# Comprobamos
! ls data
train
# comprobamos el nombrado de los archivos
! ls data/train | head -5
cat.0.jpg
cat.10000.jpg
cat.10001.jpg
cat.10002.jpg
cat.10003.jpg
ls: write error: Broken pipe

Echando un vistazo veo que hay 25.000 imágenes, 14.500 de cada clase.

Preparando la estructura de archivos

Necesitamos una carpeta por cada set, entrenamiento y validación, y dentro de estas una carpeta por cada categoría.

% mkdir $DATA_HOME_DIR/valid
# Sacamos del test de entrenamiento 2000 imágenes al azar, que serán nuestro test de validación
# Recuerda que del test de validación también necesitamos conocer la respuesta
% cd $DATA_HOME_DIR/train
g = glob('*.jpg')
shuf = np.random.permutation(g)
for i in range(2000): 
    os.rename(shuf[i], '../valid/' + shuf[i])
/home/nbuser/catsdogs/data/train
# Y separamos por categorías de imágenes
# Paciensia
% cd $DATA_HOME_DIR/valid
% mkdir cats
% mkdir dogs
% mv cat.*.jpg cats/
% mv dog.*.jpg dogs/

% cd $DATA_HOME_DIR/train
% mkdir cats
% mkdir dogs
% mv cat.*.jpg cats/
% mv dog.*.jpg dogs/
/home/nbuser/catsdogs/data/valid
/home/nbuser/catsdogs/data/train

Carga de las imágenes en Keras

Ya tenemos la estructura de archivos que necesitamos, dos sets de imágenes y cada clase en su carpeta. Ahora vamos a ver como cargarlas en el formato que Keras necesita.

% cd ~
import utils

from keras.preprocessing import image
from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten, Convolution2D, MaxPooling2D, BatchNormalization
/home/nbuser
# Imágenes que contiene un lote de trabajo,
# También llamado minibatch
batch_size = 256

# Vamos a reducir el tamaño de las imágenes
# para facilitar el testing
image_size = 30
# Generamos los batches, usamos un iterador que
# va devolviendo imágenes según las necesitemos

# Usamos rescale para normalizar los valores entre 0 y 1
gen = image.ImageDataGenerator(rescale=1./255)
train_data = gen.flow_from_directory(
                DATA_HOME_DIR+'/train/', 
                target_size=(image_size,image_size),
                class_mode='categorical', 
                shuffle=True, 
                batch_size=batch_size)

valid_data = gen.flow_from_directory(
                DATA_HOME_DIR+'/valid/', 
                target_size=(image_size,image_size),
                class_mode='categorical', 
                shuffle=True, 
                batch_size=batch_size)
Found 23000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
# Vemos que los minibatches son 64 imágenes del tamaño indicado
# con 3 canales (RGB) y que la clase la tenemos 
# en one hot encoding
minibatch = next(train_data)
print(minibatch[0].shape)
print(minibatch[1][0])
(256, 30, 30, 3)
[1. 0.]
# Siempre es recomendable ver unas cuantas
# imágenes para comprobar que todo es correcto
utils.plot_images(minibatch[0][:8], minibatch[1][:8])

png

Entrenando nuestro modelo

¡Todo listo! Vamos a probar con un modelo muy simple para ver como usar las imágenes.

model = Sequential()

model.add(Convolution2D(32, (3, 3), activation='relu', input_shape=(image_size, image_size, 3)))
model.add(BatchNormalization())
model.add(MaxPooling2D(pool_size=(3,3)))

model.add(Flatten())
model.add(Dense(64, activation='relu'))
model.add(BatchNormalization())
model.add(Dropout(0.2))

model.add(Dense(2, activation='softmax'))

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

history = model.fit_generator(
            train_data,
            steps_per_epoch=train_data.samples/train_data.batch_size,
            epochs=epochs,
            validation_data=valid_data,
            validation_steps=valid_data.samples/valid_data.batch_size)
Epoch 1/1
 6/89 [=>............................] - ETA: 9:57 - loss: 1.0433 - acc: 0.5514 

Es un modelo de prueba muy limitado y no conseguiríamos resultados espectaculares, pero funciona y entrena con nuestras imágenes, que es lo que buscábamos.

Conclusiones

Ya podemos cargar imágenes externas para usar en nuestros experimentos. Es importante saber como funciona el generador y como organizar correctamente los datos.

Fuentes