Segmentación multietiquetas — Clasificación de Imágenes

Source: Deep Learning on Medium


Go to the profile of Ruben Romo

En este artículo veremos cómo descargar directamente un set de datos desde Kaggle y luego cómo subirlos para la participación en un concurso.

El concurso de Kaggle con el cual trabajaremos en esta práctica será el siguiente: https://www.kaggle.com/c/planet-understanding-the-amazon-from-space

Hasta ahora en las prácticas anteriores al momento de clasificar las imágenes solo pasábamos una etiqueta pero sabemos que no siempre es así, por esto, ahora aprenderémos a asignar más etiquetas a las imágenes.

En el ejercicio de Kaggle notamos que son imágenes satelitales y cada imagen tiene más de una etiqueta.

Imports

Hacemos los respectivos imports

%reload_ext autoreload
%autoreload 2
%matplotlib inline
from fastai.vision import *

Si trabajamos desde google colab ya tendremos preinstalada la librería kaggle, de lo contrario podemos instalarla ejecutando el siguiente comando.

# ! pip install kaggle --upgrade

Necesitamos las credenciales de nuestra cuenta Kaggle, vamos a la sección “Mi cuenta” en kaggle y bajamos hasta encontrar la seccion de API token, creamos uno nuevo y se nos descargará el archivo json y lo subimos a nuestro notebook en colab.

Ya subidas nuestras credenciales corremos los siguientes comandos.

 ! mkdir -p ~/.kaggle/
! mv kaggle.json ~/.kaggle/

Ahora sí ya estamos listos para trabajar en la práctica y primero debemos aceptar los términos y condiciones de la competición de kaggle y corremos el siguiente código el cual creará un directorio.

path = Config.data_path()/'planet'
path.mkdir(parents=True, exist_ok=True)
path

Descargando los datos

 ! kaggle competitions download -c planet-understanding-the-amazon-from-space -f train-jpg.tar.7z -p {path} 
! kaggle competitions download -c planet-understanding-the-amazon-from-space -f train_v2.csv -p {path}
! unzip -q -n {path}/train_v2.csv.zip -d {path}

Si nos fijamos en la extensión de la base de datos podemos apreciar que está comprimida en .7zip y no en .zip como normalmente estamos acostumbrados.

Google Colab ya tiene preinstalada la librería para usar .7zip, si usamos otro servicio necesitaremos instalarla y lo haremos con el siguiente comando.

! conda install -y -c haasad eidl7zip

Luego corremos el comando para descomprimir todo lo que hemos descargado.

! 7za -bd -y -so x {path}/train-jpg.tar.7z | tar xf - -C {path}

Observaremos un poco lo que contiene el archivo .csv

df = pd.read_csv(path/'train_v2.csv')
df.head()

Si somos observadores nos podemos dar cuenta de que el archivo csv contiene el nombre de cada imagen junto con sus respectivas etiquetas.

Queremos convertir esto en algo que podamos usar para nuestro modelo, el tipo a usar es un obejeto de la clase DataBunch. Debemos de alguna manera crear un databunch como ya lo hemos hecho en prácticas anteriores, una vez obtenido esto podemos correr .show_batch() para echar un vistazo y luego podemos usar create_cnn con esto y ya podremos entrenar nuestro modelo AI.

Realmente el paso más complicado de deep learning ha sido a menudo obtener la data en una forma que se pueda modelar. Hasta ahora lo hemos hecho de varias maneras usando métodos de fábrica los cuales son tipo “Yo quiero crear este tipo de data de esta fuente con estos tipos de opciones”. Eso trabaja bien, sin embargo muchas veces necesitamos algo más flexible porque hay muchas opciones que debemos considerar:

  • ¿Dónde se encuentran los archivos?
  • ¿Cuál es el tipo de estructura que tienen?
  • ¿Cómo aparecen las etiquetas?
  • ¿Cómo se separa el set de validación?
  • ¿Cómo se hacen las transformaciones?

Por esto y más tenemos data block API. El data block API hace cada una de estas decisiones por separado. Son métodos por separado con sus propios parámetros para cada opción que tu crees o configures de la data.

Manipulando los datos y entrenando la red

Para poner esto en un DataBunch al usar data block API, debemos trabajar con ImageList y no conImageDataBunch. Esto nos asegurará que el modelo creado tenga las propiedades correctas entre ellas las de pérdida y validación para trabajar con múltiples clases/etiquetas.

tfms = get_transforms(flip_vert=True, max_lighting=0.1, max_zoom=1.05, max_warp=0.)

En esta parte por favor tómate un tiempo para analizar detenidamente el código, lo que estamos ingresando, etc. Así también recuerda que lo que hace que un modelo sea mejor que otro cae mayormente en el juego entre los valores de los parámetros.

Fíjate en las funciones a usarse como por ejemplo ImageList.from_csv, split_by_rand_pct y label_from_df.

np.random.seed(42)
src = (ImageList.from_csv(path, 'train_v2.csv', folder='train-jpg', suffix='.jpg')
.split_by_rand_pct(0.2)
.label_from_df(label_delim=' '))

Ahora creamos una variable data a la cual le pasamos el src que creamos anteriormente y le aplicamos las transformaciones y las normalizaciones.

data = (src.transform(tfms, size=128)
.databunch().normalize(imagenet_stats))

Para observar unas imágenes usamos show_batch

data.show_batch(rows=3, figsize=(12,9))

Para crear un Learner usamos la misma función que en la lección1. Yo usaré resnet50, algo adicional es que las métricas son un poco diferentes, usaremos accuracy_thresh en lugar de accuracy. En la lección 1 determinamos la predicción de la categoría dada al escoger una activación final que sea la mayor, pero aquí cada activación puede ser 0 o 1.accuracy_thresh selecciona las que están por encima de un mínimo (0.5 por defecto) y las compara con las verdaderas.

Y para Fbeta, es la métrica usada por Kaggle en esta competición. Mira aquí para más detalles.

arch = models.resnet50

Aquí podemos configurar el threshold mínimo, está en 0.2 y si no lo ingresamos usará 0.5 por defecto

acc_02 = partial(accuracy_thresh, thresh=0.2)
f_score = partial(fbeta, thresh=0.2)
learn = cnn_learner(data, arch, metrics=[acc_02, f_score])

Hallamos la mejor taza de aprendizaje.

learn.lr_find()

Y ya encontrada la graficaremos.

learn.recorder.plot()

Ahora sí podemos entrenar nuestra red.

lr = 0.01
learn.fit_one_cycle(5, slice(lr))

Grabamos nuestro estado antes de tunear nuestra red con otros valores de taza de aprendizaje o diferente número de epochs si es que consideramos prudente hacerlo.

learn.save('stage-1-rn50')

Graficamos las pérdidas

learn.recorder.plot_losses()

Exportando y subiendo a Kaggle

learn.export()

Antes de subir nuestro trabajo debemos verificar que todo esté bien y para ello descargaremos los datos de prueba que también se los puede descargar de la competición en kaggle.

! kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg.tar.7z -p {path} 
! 7za -bd -y -so x {path}/test-jpg.tar.7z | tar xf - -C {path}
! kaggle competitions download -c planet-understanding-the-amazon-from-space -f test-jpg-additional.tar.7z -p {path}
! 7za -bd -y -so x {path}/test-jpg-additional.tar.7z | tar xf - -C {path}

Creamos una variable test en la cual asignamos una imagen de prueba.

test = ImageList.from_folder(path/'test-jpg').add(ImageList.from_folder(path/'test-jpg-additional'))

La cargamos en nuestro modelo.

learn = load_learner(path, test=test)
preds, _ = learn.get_preds(ds_type=DatasetType.Test)

Y ahora seccionamos las etiquetas predichas si es que se cumplen que tienen un threshold mayor a 0.2

thresh = 0.2
labelled_preds = [' '.join([learn.data.classes[i] for i,p in enumerate(pred) if p > thresh]) for pred in preds]

Imprimos las primeras 5.

labelled_preds[:5]

Creamos una variable en la que asignaremos los nombres de las imágenes para posteriormente agregar las etiquetas predichas y que nos sirva para enviar nuestro reporte a la competición

fnames = [f.name[:-4] for f in learn.data.test_ds.items]

Con la ayuda de pandas creamos un DataFrame

df = pd.DataFrame({'image_name':fnames, 'tags':labelled_preds}, columns=['image_name', 'tags'])

Y al imprimirlo.

En estas imágenes de prueba los creadores de la competición ya saben cuales son las etiquetas correctas y en esto se basa nuestro reporte.

Convertimos nuestro DataFrame a .csv para poderlo subir a kaggle

df.to_csv(path/'submission.csv', index=False)

Y solo nos falta subirlo, lo haremos con el siguiente comando.

! kaggle competitions submit planet-understanding-the-amazon-from-space -f {path/'submission.csv'} -m "My submission"

Mi puntaje fue de 92.364% el cual es excelente.

Pueden ver el python notebook en github

https://github.com/ai-saturdays-guayaquil/Curso/blob/master/Lesson3DL.ipynb

Espero que esta guía les sea de mucha ayuda. No se olviden de dejar los aplausos (puedes dar 50 ;) ).