Transfer learning

29 de Mayo de 2017

En machine learning, se conoce como transfer learning cuando aprovechamos el conocimiento adquirido para resolver un problema y lo usamos para resolver otro problema similar.

Actualmente donde más se usa es en la clasificación de imagenes.

Supongamos por ejemplo que en algún momento alguien diseñó y entrenó un modelo capaz de reconocer autos. Aplicando transfer learning podría intentar reutilizar ese modelo, adaptándolo para hacer un nuevo modelo que reconozca camiones.

¿Y qué gano haciendo transfer learning? ¿Cuál es la motivación de hacerlo?

Para el caso de la clasificación de imagenes, los mejores resultados se obtienen usando redes neuronales convolucionales (ConvNets1 2). Las ConvNets son redes neuronales profundas (deep learning) donde algunas de sus capas funcionan como filtros convolucionales3. Con el entrenamiento, estos filtros se adaptan reconociendo características de las imágenes que queremos clasificar.

Suponiendo que quiero hacer una ConvNet de cero, el primer problema grande que voy a tener es definir la arquitectura, ¿cuántas capas convolucionales? ¿cuántos filtros? ¿de qué tamaño? Para lograr buenos resultados esto no es una tarea sencilla y requiere de mucho conocimiento y mucha práctica.

El segundo problema es el entrenamiento. Por lo general las ConvNets son muy costosas de entrenar. Tienen muchos parámetros y se necesitan muchísimos datos de entrada.

Si alguien ya resolvió un problema similar al que quiero resolver, me facilitaría mucho poder aprovechar el camino ya recorrido (la arquitectura y el entrenamiento).

ImageNet

ImageNet es un proyecto para la investigación en el reconocimientos de objetos y visión por computadora. Este proyecto cuenta con una base de datos de millones de imágenes con diferentes objetos etiquetados. Estas imágenes son utilizadas por investigadores y estudiantes para desarrollar sus modelos.

Desde el 2010 ImageNet hace anualmente un desafío donde se presentan equipos de investigadores de todo el mundo. Gana el equipo que, dado un conjunto de fotografías nuevas (150000 fue en el 2016), reconoce 1000 clases de objetos diferentes en estas con el menor error.

Lo interesante es que muchos de los modelos que ganan estos desafíos son liberados y cualquiera de nosotros los podemos usar. Son modelos que reconocen 1000 categorías de objetos diferentes lo cual hace que sean bastante genéricos y se puedan adaptar a muchos problemas. Los filtros aprendidos por las capas convolucionales de estos modelos sirven para muchos problemas de reconocimiento y visión. Los modelos más conocidos son: VGG16, VGG19, ResNet50, InceptionV3, etc.

Ejemplo con VGG16

Siguiendo una idea similar a la planteada en este post en el blog de keras, reutilizando VGG16 y pocas líneas de código agregadas, voy a resolver el problema "Dogs vs Cats" de kaggle.

Problema "Dogs vs Cats"

El problema consiste en identificar en 2000 fotos, cuales son fotos de perros y cuales son fotos de gatos. Para esto kaggle nos da para entrenar 12500 fotos de perros y 12500 fotos de gatos ya clasificadas.

Algunas de estas fotos son las siguientes:



Solución usando keras y VGG16

Para resolver el problema voy a usar keras (una de las librerías de deep learning más usadas). A partir de la versión 1.1 varios de los modelos de ImageNet ya vienen integrados y se pueden instanciar y usar facilmente.

El código completo está acá (link), son 50 lineas. Esta es la parte más interesante:


# Instancio vgg16 con los pesos de imagenet
vgg16 = VGG16(weights='imagenet')

# Me creo un modelo igual a VGG con la diferencia de la ultima capa.
# En vez de utilizar la ultima capa que clasifica entre 1000 clases de objetos
# utilizo una capa propia que clasifica entre gatos y perros (0=gatos y 1=perros). 
block5_pool_output = vgg16.get_layer('block5_pool').output
x = Flatten(input_shape=(7,7,512))(block5_pool_output)
x = Dense(256, activation='relu')(x)
x = Dropout(0.6)(x) # regularización
x = Dense(1, activation='sigmoid')(x)
model = Model(input=vgg16.input, output=x)

# Marco como entrenable solo la ultima capa. No entreno la parte convolucional
for layer in model.layers[:18]:
    layer.trainable = False 

Lo que hago es instanciar el modelo VGG16 y sustituirle la última capa. En vez de clasificar entre 1000 clases de objetos, que clasifique solamente entre perros y gatos (esto se conoce como hacer un "finetuning" del modelo).

Haciendo esto y entrenando solo la capa sustituida, se logra una precisión de validación de casi un 97%.


...
Epoch 48/50
80/80 [==============================] - 52s - loss: 0.1121 - acc: 0.9577 - val_loss: 0.0890 - val_acc: 0.9681
Epoch 49/50
80/80 [==============================] - 52s - loss: 0.1236 - acc: 0.9587 - val_loss: 0.0934 - val_acc: 0.9650
Epoch 50/50
80/80 [==============================] - 51s - loss: 0.1203 - acc: 0.9475 - val_loss: 0.0878 - val_acc: 0.9694

El caso de los perros y gatos son categorías que los modelos de ImageNet ya clasifican, por eso solamente entrenando la última capa ya es suficiente. Para otro tipos de problemas se puede volver a entrenar alguna de las capas convolucionales.

Otras aplicaciones de transfer learning

El ejemplo de los perros y gatos puede parecer poco útil, pero esta misma técnica se puede trasladar a otras aplicaciones más útiles.

Por ejemplo, Jeremy Howard comenta en este video (link), que en su empresa anterior, Enlitic, utilizando una técnica muy parecida a esta con modelos preentrenados de ImageNet e imágenes de tomografías, logró hacer un modelo que clasifica tumores entre benignos y malignos de manera más precisa que un panel de 4 radiólogos.

Por mas información sobre transfer learning en ConvNets ver:
http://cs231n.github.io/transfer-learning/

1 Introducción a redes convolucionales - Adam Geitgey
2 Understanding Convolutions - Chris Olah
2 Convolution matrix - Wikipedia


Comentarios

Los comentarios de este post hacelo en el siguiente tweet. Gracias.