Clase 7: Transfer Learning y Data Augmentation
Crear arquitecturas de CNN desde cero es una tarea compleja y que requiere de mucho conocimiento y experiencia. Afortunadamente, existen diversas arquitecturas famosas que han sido probadas y testeadas en el tiempo, las cuáles pueden ser utilizadas como backbones para distintas tareas de Visión por Computador.
Probablemente la primera arquitectura famosa en poder realizar tareas importantes de reconocimiento de imagen. Diseñada especialmente para reconocimiento de dígitos, introduce los bloques de convolución más pooling para luego conectarse con FFN.
Adaptive Pooling
La mayoría de arquitecturas más modernas utiliza una capa llamada Adaptive Pooling antes del proceso de Flatten. El Adaptive Pooling es una especie de Pooling inverso, donde uno define el tamaño del output, y automáticamente se calcula el Kernel, Stride, Padding, etc. necesario para obtener ese tamaño.
Eso garantiza que cualquier tamaño de imagen puede pasar por la red sin romper las dimensiones necesarias para la transición al MLP.
Ganó el concurso Imagenet (ILSVRC) en 2012 por un largo margen (algo impensado para ese tiempo). Introdujo los conceptos de ReLU, Dropout y Aceleración por GPU. Esta arquitectura está disponible en
torchvision.
La arquitectura de Torchvision está inspirada en una versión alternativa de Alexnet. Esto probablemente no será corregido ya que no es una arquitectura que se utilice comunmente en la actualidad.
Presentaron las primeras redes relativamente profundas con Kernels pequeños de \(3 \times 3\). Su propuesta incluye Redes de hasta 19 capas.
import torchvision
torchvision.models.vgg16(weights = "IMAGENET1K_V1")
## Versión con Batchnorm
torchvision.models.vgg16_bn(weights = "IMAGENET1K_V1")torchvision incluye las arquitecturas de 11, 13, 16 y 19 capas, además de variantes que incluyen Batchnorm (que en eltiempo del paper no existían aún).
Introduce las “Pointwise Convolutions” (Convoluciones de 1x1) que permiten reducir la complejidad de canales (mediante una combinación lineal) manteniendo las dimensiones de la imagen. Además introduce los Inception Modules, que combinan resultados de Kernels de distinto tamaño. Fue la Arquitectura ganadora de ILSVRC 2014.
Introduce las conexiones residuales, lo cual permite evitar el problema del vanishing gradient para redes muy profundas. Es la Arquitectura ganadora de ILSVRC 2015.
Esta arquitectura se puede encontrar tanto en torchvision como timm. Recomiendo timm, ya que hay muchas más variantes, mejor mantención y procesos de entrenamiento actualizados.
import timm
model = timm.create_model("resnet50", pretrained = True)
## Listar todas las versiones de Resnet disponibles
timm.list_models("resnet*")Introducen el concepto de Compound Scaling que permite cambiar la escala de profundidad (número de capas en la red), ancho (número de canales en cada capa) y resolución (dimensiones de la imagen) para poder mejorar la performance. Permite crear resultados al nivel del estado del arte con muchísimos menos parámetros.
Las imágenes presentan resoluciones variadas, que van desde \(4288 \times 2848\) hasta \(75 \times 56\) píxeles. Además, se encuentran normalizadas restando la media por canal \([0.485,0.456,0.406]\) y dividiendo por la desviación estándar correspondiente \([0.229,0.224,0.225]\).
🤔
Las dos variantes más conocidas son ImageNet-1K, que contiene 1.281.167, 50.000 y 100.000 imágenes para los conjuntos de train, validation y test, respectivamente, distribuidas en 1000 categorías; y ImageNet-21K, que incluye 14.197.122 imágenes organizadas en 21.841 clases.
Debido a la relevancia y complejidad de este conjunto de datos, la mayoría de los backbones han sido preentrenados en él. Gracias a esto, las distintas arquitecturas “aprenden a ver” a partir del conocimiento adquirido mediante este dataset.
Debido a que muchas arquitecturas pueden/saben ver en un dataset tan complejo como Imagenet. ¿Sería posible utilizar ese conocimiento en otro dataset?
Dataset Público/alta complejidad
Normalmente se utilizan datos públicos y de alta complejidad y se utiliza para pre-entrenar una arquitectura.
Pre-entrenamiento
Se entrena una arquitectura para una tarea en específico con los detalles del dataset a utilizar.
Fine-Tuning
Se carga la arquitectura pre-entrenada, con los pesos obtenidos en el pre-entrenamiento y se ajusta el prediction head para la nueva tarea y se vuelve a entrenar el modelo.
Freezing Layers
Se refiere a congelar los parámetros del backbone pre-entrenado, es decir, estos no se actualizan. Este paso es opcional, y en ocasiones puede funcionar de mejor manera que un Full-Fine-Tuning
En general el proceso de Preprocesamiento de Imágenes es bastante más engorroso que el de datos tabulares. Afortunadamente Pytorch tiene algunos
utilitiesque permiten hacer el proceso más sencillo:
ImageFolder considerará cada carpeta como una clase y los elementos (imágenes) dentro de dicha clase como instancia de la clase en cuestión.
from torchvision.dataset import ImageFolder
train_data = ImageFolder("path/to/train/images", transform = None)
validation_data = ImageFolder("path/to/validation/images", transform = None)
test_data = ImageFolder("path/to/test/images", transform = None)Además ImageFolder posee un parámetro llamado transform en el cuál se pueden ingresar transformaciones a los datos para realizar procesos de Data Augmentation.
Ojo
ImageFolder entrega los datos como una Imagen PIL. Por lo tanto, es necesario aplicar procesamientos que permitan su transformación en Tensor.
Corresponde a un proceso de generación de datos sintéticos. Este proceso se puede utilizar para:
Albumentations
Existen diversas librerías que permiten generar Aumento de Datos. La librerías más famosas son Albumentations y Kornia. Albumentations, permite transformaciones extremadamente eficientes en CPU, mientras que Kornia hace lo mismo pero en GPU. Debido a las limitaciones de GPU que contamos, utilizaremos Albumentations, de manera tal de balancear procesamiento tanto en CPU como en GPU.
Normalmente este tipo de transformaciones entrega mejores resultados cuando se generan de manera aleatoria y on-the-fly. Es decir, se genera el aumento de datos en la carga de datos durante el entrenamiento.
Albumentations espera que la imagen venga como Numpy Array. Además es una librería bastante quisquillosa, por lo que toma un rato acostumbrarse. Pero su eficiencia y utilidad hace que valga la pena.
ToTensor() pero está deprecada y no debería usarse.
Como su nombre lo indica, la transformación se aplicará con una cierta probabilidad, lo que permitirá que cada epoch haya mayor variabilidad.
Existen un sinnúmero de transformaciones que se pueden aplicar. La lista completa se puede encontrar acá. Y existen transformaciones que incluso permiten simular niebla, lluvia, nieve, sepia, Zoom, y variados otros efectos.
Aplicar estas transformaciones es de extremo cuidado ya que para tareas más complejas como Semantic Segmentation, Object Detection, Keypoint Detection, se debe aplicar dichas transformaciones también a las etiquetas.
