Alberto Beiz

Mis pruebas y experimentos.

Contacta sin miedo:

Como enviar tus resultados a una competición de Kaggle

Tareas previas

Objetivos

import utils

from keras.preprocessing import image
from keras.applications.resnet50 import ResNet50
from keras.models import Model, Sequential
from keras.layers import Dense, Dropout, Flatten, BatchNormalization, GlobalAveragePooling2D
from keras.optimizers import Adam
from keras.utils.np_utils import to_categorical

import numpy as np
import os

working_dir = os.getcwd()
LESSON_HOME_DIR = working_dir + '/catsdogs'
DATA_HOME_DIR = LESSON_HOME_DIR + '/data'
TEST_HOME_DIR = LESSON_HOME_DIR + '/test'

# Tamaño del minibatch
batch_size = 64

# Tamaño de las imágenes
image_size = 224
# Cargamos las imágenes
gen = image.ImageDataGenerator()
train_data = gen.flow_from_directory(
                DATA_HOME_DIR+'/train/', 
                target_size=(image_size,image_size),
                class_mode='categorical', 
                shuffle=False, 
                batch_size=batch_size)

valid_data = gen.flow_from_directory(
                DATA_HOME_DIR+'/valid/', 
                target_size=(image_size,image_size),
                class_mode='categorical', 
                shuffle=False, 
                batch_size=batch_size)
Found 23000 images belonging to 2 classes.
Found 2000 images belonging to 2 classes.
# Hacemos los mismo que en el post de VGG
# Precalculamos la salida de Resnet
# para poder hacer nuestros experimentos con la cpu
resnet = ResNet50(include_top=False, weights='imagenet', input_shape=(image_size,image_size,3))
train_pred = resnet.predict_generator(train_data, train_data.samples/batch_size, verbose=1)
valid_pred = resnet.predict_generator(valid_data, valid_data.samples/batch_size, verbose=1)

train_pred_labels = to_categorical(train_data.classes)
valid_pred_labels = to_categorical(valid_data.classes)
360/359 [==============================] - 370s 1s/step
32/31 [==============================] - 31s 975ms/step
# Guardamos todos los resultados
utils.save_array('resnet_train_data.bc', train_pred)
utils.save_array('resnet_valid_data.bc', valid_pred)

utils.save_array('resnet_train_labels.bc', train_pred_labels)
utils.save_array('resnet_valid_labels.bc', valid_pred_labels)
train_pred = utils.load_array('resnet_train_data.bc')
valid_pred = utils.load_array('resnet_valid_data.bc')

train_pred_labels = utils.load_array('resnet_train_labels.bc')
valid_pred_labels = utils.load_array('resnet_valid_labels.bc')
# Creamos un modelo muy sencillo para
# clasificar la salida de las capas convolucionales
# de Resnet en nuestras dos clases
top_model = Sequential()

top_model.add(GlobalAveragePooling2D(input_shape=train_pred[0].shape))
top_model.add(Dropout(0.7))

top_model.add(Dense(2, activation='softmax'))
top_model.compile(optimizer=Adam(),
                    loss='categorical_crossentropy', 
                    metrics=['accuracy'])
top_model.fit(train_pred, train_pred_labels,
                batch_size=batch_size,
                epochs=3,
                validation_data=(valid_pred, valid_pred_labels))
Train on 23000 samples, validate on 2000 samples
Epoch 1/3
23000/23000 [==============================] - 2s 79us/step - loss: 0.2042 - acc: 0.9261 - val_loss: 0.0768 - val_acc: 0.9690
Epoch 2/3
23000/23000 [==============================] - 1s 55us/step - loss: 0.1125 - acc: 0.9596 - val_loss: 0.0714 - val_acc: 0.9695
Epoch 3/3
23000/23000 [==============================] - 1s 55us/step - loss: 0.1049 - acc: 0.9621 - val_loss: 0.0717 - val_acc: 0.9730

Aplicando nuestro modelo al set de test

El set de test es con el que Kaggle evalua nuestras predicciones, no conocemos las clases de este test, es lo más parecido a usar el modelo en la vida real.

% cd catsdogs
import zipfile

zip = zipfile.ZipFile('test.zip')
zip.extractall('test')
/home/nbuser/catsdogs
% ls test
test/
# Cambiamos el nombre por no repetir test
mv test/test test/unknown
rm test.zip
% cd ~

gen = image.ImageDataGenerator()
test_data = gen.flow_from_directory(
                TEST_HOME_DIR, 
                target_size=(image_size, image_size),
                class_mode='categorical', 
                shuffle=False, 
                batch_size=batch_size)
/home/nbuser
Found 12500 images belonging to 1 classes.
# precalculamos resnet
resnet_pred = resnet.predict_generator(test_data, test_data.samples/batch_size, verbose=1)
196/195 [==============================] - 178s 910ms/step
resnet_pred.shape
(12500, 1, 1, 2048)
test_pred = top_model.predict(resnet_pred, test_data.samples//batch_size, verbose=1)
12500/12500 [==============================] - 0s 12us/step
# 12500 elementos con probabilidad de ser perro
# y de ser gato
test_pred.shape
(12500, 2)
test_pred[0]
array([7.3065705e-05, 9.9992692e-01], dtype=float32)
utils.save_array('test_pred_data.bc', test_pred)
test_pred = utils.load_array('test_pred_data.bc')
filenames = test_data.filenames

Kaggle espera que le mandemos un csv con el siguiente formato:

imageId,isDog

1242, .3984

3947, .1000

4539, .9082

2345, .0000

Podéis comprobarlo en el archivo sample_submission.csv. Asi que toca preparar nuestras predicciones para presentarlas en el formato adecuado. Además haremos un pequeño truco para mejorar nuestra puntuación.

isdog = test_pred[:,1]

# Con este truquillo evitamos errores
# demasiado grandes que nos penalizarían mucho
isdog = isdog.clip(min=0.02, max=0.98)

# Formato de salida
ids = np.array([int(f[8:f.find('.')]) for f in filenames])
subm = np.stack([ids,isdog], axis=1)
# Guardamos el csv
submission_file_name = LESSON_HOME_DIR + '/submission1.csv'
np.savetxt(submission_file_name, subm, fmt='%d,%.5f', header='id,label', comments='')
# Lo enviamos a Kaggle que nos responde con nuestra puntuación
! kg submit $LESSON_HOME_DIR/submission1.csv
0.08834

Ahora puedes ir al leaderboard en la web de Kaggle y mirar tu posición

Conclusiones

Fuentes