Train self-supervised vision transformers on overhead imagery with Amazon SageMaker’ Entrenar transformadores de visión auto-supervisados en imágenes aéreas con Amazon SageMaker.

Train self-supervised vision transformers on overhead imagery with Amazon SageMaker

Esta es una publicación de blog invitada escrita en colaboración con Ben Veasey, Jeremy Anderson, Jordan Knight y June Li de Travelers.

Las imágenes satelitales y aéreas brindan información sobre una amplia gama de problemas, incluyendo la agricultura de precisión, la evaluación de riesgos de seguros, el desarrollo urbano y la respuesta a desastres. Sin embargo, el entrenamiento de modelos de aprendizaje automático (ML) para interpretar estos datos se ve obstaculizado por los costosos y laboriosos esfuerzos de anotación humana. Una forma de superar este desafío es a través del aprendizaje autodirigido (SSL). Al entrenar con grandes cantidades de datos de imagen no etiquetados, los modelos de autoaprendizaje aprenden representaciones de imagen que se pueden transferir a tareas posteriores, como la clasificación o segmentación de imágenes. Este enfoque produce representaciones de imagen que generalizan bien a datos no vistos y reduce la cantidad de datos etiquetados necesarios para construir modelos posteriores de alto rendimiento.

En esta publicación, demostramos cómo entrenar transformadores de visión de autoaprendizaje en imágenes aéreas utilizando Amazon SageMaker. Travelers colaboró con el Laboratorio de Soluciones de Aprendizaje Automático de Amazon (ahora conocido como el Centro de Innovación de IA Generativa) para desarrollar este marco de trabajo y apoyar y mejorar los casos de uso de modelos de imágenes aéreas. Nuestra solución se basa en el algoritmo DINO y utiliza la biblioteca paralela de datos distribuidos de SageMaker (SMDDP) para dividir los datos en varias instancias de GPU. Una vez que se completa el preentrenamiento, las representaciones de imagen DINO se pueden transferir a una variedad de tareas posteriores. Esta iniciativa dio lugar a mejoras en el rendimiento del modelo dentro del espacio de Datos y Analíticas de Travelers.

Resumen de la solución

El proceso de dos pasos para el preentrenamiento de transformadores de visión y su transferencia a tareas posteriores supervisadas se muestra en el siguiente diagrama.

En las siguientes secciones, proporcionamos un tutorial paso a paso de la solución utilizando imágenes satelitales del conjunto de datos BigEarthNet-S2. Nos basamos en el código proporcionado en el repositorio DINO.

Requisitos previos

Antes de comenzar, necesitas tener acceso a una instancia de cuaderno SageMaker y un bucket de Amazon Simple Storage Service (Amazon S3).

Preparar el conjunto de datos BigEarthNet-S2

BigEarthNet-S2 es un archivo de referencia que contiene 590,325 imágenes multiespectrales recopiladas por el satélite Sentinel-2. Las imágenes documentan la cobertura terrestre, o características físicas de la superficie, de diez países europeos entre junio de 2017 y mayo de 2018. Los tipos de cobertura terrestre en cada imagen, como pastizales o bosques, están anotados según 19 etiquetas. A continuación se muestran algunas imágenes RGB de ejemplo y sus etiquetas.

El primer paso en nuestro flujo de trabajo es preparar el conjunto de datos BigEarthNet-S2 para el entrenamiento y la evaluación de DINO. Comenzamos descargando el conjunto de datos desde la terminal de nuestra instancia de cuaderno SageMaker:

wget https://bigearth.net/downloads/BigEarthNet-S2-v1.0.tar.gz
tar -xvf BigEarthNet-S2-v1.0.tar.gz

El conjunto de datos tiene un tamaño de aproximadamente 109 GB. Cada imagen se almacena en su propia carpeta y contiene 12 canales espectrales. Se utilizan tres bandas con una resolución espacial de 60 m (altura/ancho de píxel de 60 metros) para identificar aerosoles (B01), vapor de agua (B09) y nubes (B10). Seis bandas con una resolución espacial de 20 m se utilizan para identificar vegetación (B05, B06, B07, B8A) y distinguir entre nieve, hielo y nubes (B11, B12). Tres bandas con una resolución espacial de 10 m ayudan a capturar la luz visible e infrarroja cercana (B02, B03, B04, B8/B8A). Además, cada carpeta contiene un archivo JSON con los metadatos de la imagen. Se proporciona una descripción detallada de los datos en la Guía de BigEarthNet.

Para realizar análisis estadísticos de los datos y cargar imágenes durante el entrenamiento de DINO, procesamos los archivos de metadatos individuales en un archivo Parquet común de geopandas. Esto se puede hacer utilizando los paquetes auxiliares BigEarthNet Common y BigEarthNet GDF Builder:

python -m bigearthnet_gdf_builder.builder build-recommended-s2-parquet BigEarthNet-v1.0/

El archivo de metadatos resultante contiene el conjunto de imágenes recomendado, que excluye 71,042 imágenes que están completamente cubiertas por nieve estacional, nubes y sombras de nubes. También contiene información sobre la fecha de adquisición, ubicación, cobertura terrestre y división de entrenamiento, validación y prueba para cada imagen.

Almacenamos las imágenes y el archivo de metadatos de BigEarthNet-S2 en un bucket de S3. Debido a que utilizamos imágenes en color real durante el entrenamiento de DINO, solo cargamos las bandas roja (B04), verde (B03) y azul (B02):

aws s3 cp final_ben_s2.parquet s3://bigearthnet-s2-dataset/metadata/
aws s3 cp BigEarthNet-v1.0/ s3://bigearthnet-s2-dataset/data_rgb/ \
    --recursive \
    --exclude "*" \
    --include "_B02.tif" \
    --include "_B03.tif" \ 
    --include "_B04.tif"

El conjunto de datos tiene un tamaño aproximado de 48 GB y tiene la siguiente estructura:

bigearthnet-s2-dataset/                                    Bucket de Amazon S3
├── metadata/
│ └── final_ben_s2.parquet 
└── dataset_rgb/
  ├── S2A_MSIL2A_20170613T101031_0_45/
  │ └── S2A_MSIL2A_20170613T101031_0_45_B02.tif            Canal azul
  │ └── S2A_MSIL2A_20170613T101031_0_45_B03.tif            Canal verde
  │ └── S2A_MSIL2A_20170613T101031_0_45_B04.tif            Canal rojo

Entrenar modelos DINO con SageMaker

Ahora que nuestro conjunto de datos ha sido cargado en Amazon S3, pasamos a entrenar modelos DINO en BigEarthNet-S2. Como se muestra en la siguiente figura, el algoritmo DINO pasa diferentes recortes globales y locales de una imagen de entrada a las redes de estudiante y profesor. La red de estudiante aprende a igualar la salida de la red de profesor minimizando la pérdida de entropía cruzada. Los pesos del estudiante y del profesor están conectados por un promedio móvil exponencial (EMA).

Hacemos dos modificaciones al código original de DINO. Primero, creamos una clase de conjunto de datos personalizado de PyTorch para cargar las imágenes de BigEarthNet-S2. El código fue escrito inicialmente para procesar datos de ImageNet y espera que las imágenes estén almacenadas por clase. Sin embargo, BigEarthNet-S2 es un conjunto de datos de múltiples etiquetas donde cada imagen reside en su propia subcarpeta. Nuestra clase de conjunto de datos carga cada imagen utilizando la ruta de archivo almacenada en los metadatos:

import pandas as pd
import rasterio
from PIL import Image
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils
 
OPTICAL_MAX_VALUE = 2000

LAND_COVER_LABELS = [
    "Tejido urbano",
    "Unidades industriales o comerciales",
    "Tierra de cultivo",
    "Cultivos permanentes",
    "Pastizales",
    "Patrones de cultivo complejos",
    "Terrenos principalmente ocupados por agricultura, con áreas significativas de vegetación natural",
    "Áreas agroforestales",
    "Bosque caducifolio",
    "Bosque de coníferas",
    "Bosque mixto",
    "Pastizales naturales y áreas con vegetación escasa",
    "Turberas, brezales y vegetación esclerófila",
    "Bosque mixto transicional, arbusto",
    "Playas, dunas, arenas",
    "Humedales interiores",
    "Humedales costeros",
    "Aguas interiores",
    "Aguas marinas",
]
 
class BigEarthNetDataset(Dataset):
     """
     Clase de conjunto de datos de PyTorch que carga las imágenes de BigEarthNet-S2 desde un archivo de metadatos.

     Args: 
          metadata_file: ruta al archivo de metadatos 
          data_dir: directorio donde se encuentra BigEarthNet-S2  
          split: partición de entrenamiento, validación o prueba
          transform: transformaciones aplicadas a la imagen de entrada
     """
     def __init__(self, metadata_file, data_dir, split="train", transform=None):
        # rutas de archivos de imagen desde los metadatos
        metadata = pd.read_parquet(metadata_file)
        self.metadata_split = metadata[metadata["original_split"] == split]
        self.data_dir = data_dir
        self.patch_names = self.metadata_split["name"].tolist()
 
        # etiquetas de cobertura terrestre codificadas en one-hot 
        multiclass_labels = self.metadata_split.new_labels.tolist()
        self.labels = self.get_multi_onehot_labels(multiclass_labels)

        # transformaciones        
        self.transform = transform
 
    def __len__(self):
        """Devuelve la longitud del conjunto de datos."""
        return len(self.metadata_split)
 
    def __getitem__(self, index):
        """Devuelve la imagen y la etiqueta para un índice dado."""
        patch_name = self.patch_names[index]
        file_path = os.path.join(self.data_dir, patch_name)
    
    # generar imagen RGB
        canal_r = rasterio.open(os.path.join(file_path, patch_name + "_B04.tif")).read(1)
        canal_g = rasterio.open(os.path.join(file_path, patch_name + "_B03.tif")).read(1)
        canal_b = rasterio.open(os.path.join(file_path, patch_name + "_B02.tif")).read(1)
 
        imagen = np.stack([canal_r, canal_g, canal_b], axis=2)
        imagen = imagen / OPTICAL_MAX_VALUE * 255
        imagen = np.clip(imagen, 0, 225).astype(np.uint8)
    
        # aplicar transformaciones de imagen
        imagen = Image.fromarray(imagen, mode="RGB")
        if self.transform is not None:
            imagen = self.transform(imagen)
 
        # cargar etiqueta
        etiqueta = self.labels[index]
 
        return imagen, etiqueta
  
    def get_multi_onehot_labels(self, multiclass_labels):
        """Convierte las etiquetas BEN-19 en un vector codificado en one-hot."""
        targets = torch.zeros([len(multiclass_labels), len(LAND_COVER_LABELS)])
        for index, img_labels in enumerate(multiclass_labels):
            for label in img_labels:
                index_hot = LAND_COVER_LABELS.index(label)
                targets[index, index_hot] = 1.
        return targets

Esta clase de conjunto de datos se llama en main_dino.py durante el entrenamiento. Aunque el código incluye una función para codificar en one-hot los labels de la cobertura terrestre, estos labels no son utilizados por el algoritmo DINO.

El segundo cambio que realizamos al código de DINO es agregar soporte para SMDDP. Agregamos el siguiente código a la función init_distributed_mode en el archivo util.py:

Función init_distributed_mode en el archivo util.py:

def init_distributed_mode(args):
     if json.loads(
          os.environ.get('SM_FRAMEWORK_PARAMS', '{}'))
         .get('sagemaker_distributed_dataparallel_enabled', False)
     ): 
          # lanzar entrenamiento con SMDDP 
          dist.init_process_group(backend='smddp')
          args.word_size = dist.get_world_size() 
          args.gpu = int(os.environ['LOCAL_RANK'])

Con estos ajustes, estamos listos para entrenar modelos DINO en BigEarthNet-S2 utilizando SageMaker. Para entrenar en múltiples GPUs o instancias, creamos un Estimador de SageMaker PyTorch que ingiere el script de entrenamiento de DINO, las rutas de archivos de imagen y metadatos, y los hiperparámetros de entrenamiento:

import time
from sagemaker.pytorch import PyTorch

# cubo de salida donde se cargan los artefactos finales del modelo 
DINO_OUTPUT_BUCKET = 'dino-models'

# rutas en la instancia de entrenamiento  
sm_metadata_path = '/opt/ml/input/data/metadata'              
sm_data_path = '/opt/ml/input/data/train'                     
sm_output_path = '/opt/ml/output/data'                        
sm_checkpoint_path = '/opt/ml/checkpoints'                

# nombre del trabajo de entrenamiento
dino_base_job_name = f'dino-model-{int(time.time())}'

# crear Estimador de SageMaker
estimator = PyTorch(
    base_job_name=dino_base_job_name,
    source_dir='ruta/a/aerial_featurizer',
    entry_point='main_dino.py',
    role=role,
    framework_version="1.12",
    py_version="py38",
    instance_count=1,
    instance_type="ml.p3.16xlarge",    
    distribution = {'smdistributed':{'dataparallel':{'enabled': True}}},        
    volume_size=100,
    sagemaker_session=sagemaker_session,
    hyperparameters = {
        # hiperparámetros pasados al script de punto de entrada
        'arch': 'vit_small',
        'patch_size': 16,
        'metadata_dir': sm_metadata_path,
        'data_dir': sm_data_path,
        'output_dir': sm_output_path,
        'checkpoint_dir': sm_checkpoint_path,
        'epochs': 100,
        'saveckp_freq': 20,
    },
    max_run=24*60*60,               
    checkpoint_local_path = sm_checkpoint_path,
    checkpoint_s3_uri =f's3://{DINO_OUTPUT_BUCKET}/checkpoints/{base_job_name}', 
    debugger_hook_config=False,                           
)

Este código especifica que entrenaremos un modelo pequeño de transformador de visión (21 millones de parámetros) con un tamaño de parche de 16 durante 100 épocas. Es una buena práctica crear un nuevo checkpoint_s3_uri para cada trabajo de entrenamiento para reducir el tiempo de descarga inicial de los datos. Debido a que estamos usando SMDDP, debemos entrenar en una instancia ml.p3.16xlarge, ml.p3dn.24xlarge o ml.p4d.24xlarge. Esto se debe a que SMDDP solo está habilitado para las instancias multi-GPU más grandes. Para entrenar en tipos de instancia más pequeños sin SMDDP, deberá eliminar los argumentos distribution y debugger_hook_config del estimador.

Después de haber creado el Estimador de SageMaker PyTorch, lanzamos el trabajo de entrenamiento llamando al método fit. Especificamos los datos de entrenamiento de entrada utilizando los URIs de Amazon S3 para los metadatos e imágenes de BigEarthNet-S2:

# llamar a fit para comenzar el entrenamiento
estimator.fit(
    inputs={
        'metadata': 's3://bigearthnet-s2-dataset/metadata/',
        'train': 's3://bigearthnet-s2-dataset/data_rgb/',
    },
    wait=False
)

SageMaker inicia la instancia, copia el script de entrenamiento y las dependencias, y comienza el entrenamiento de DINO. Podemos monitorear el progreso del trabajo de entrenamiento desde nuestro notebook de Jupyter utilizando los siguientes comandos:

# monitorear entrenamiento
training_job_name = estimator.latest_training_job.name 
attached_estimator = PyTorch.attach(training_job_name)
attached_estimator.logs()

También podemos supervisar las métricas de la instancia y ver los archivos de registro en la consola de SageMaker bajo Trabajos de entrenamiento. En las siguientes figuras, trazamos la utilización de la GPU y la función de pérdida para un modelo DINO entrenado en una instancia ml.p3.16xlarge con un tamaño de lote de 128.

Durante el entrenamiento, la utilización de la GPU es del 83% de la capacidad de ml.p3.16xlarge (8 GPUs NVIDIA Tesla V100) y el uso de la VRAM es del 85%. La función de pérdida disminuye constantemente con cada época, lo que indica que las salidas de las redes del estudiante y del profesor se están volviendo más similares. En total, el entrenamiento dura aproximadamente 11 horas.

Transferencia de aprendizaje a tareas posteriores

Nuestro modelo DINO entrenado se puede transferir a tareas posteriores como clasificación de imágenes o segmentación. En esta sección, utilizamos las características pre-entrenadas de DINO para predecir las clases de cobertura de suelo para imágenes en el conjunto de datos BigEarthNet-S2. Como se muestra en el siguiente diagrama, entrenamos un clasificador lineal multi-etiqueta sobre las características congeladas de DINO. En este ejemplo, la imagen de entrada está asociada con las coberturas de tierra de cultivo y pastizales.

La mayoría del código para el clasificador lineal ya está en su lugar en el repositorio original de DINO. Hacemos algunos ajustes para nuestra tarea específica. Como antes, utilizamos el conjunto de datos personalizado BigEarthNet para cargar imágenes durante el entrenamiento y la evaluación. Las etiquetas de las imágenes se codifican en caliente como vectores binarios de 19 dimensiones. Utilizamos la entropía cruzada binaria para la función de pérdida y calculamos la precisión promedio para evaluar el rendimiento del modelo.

Para entrenar el clasificador, creamos un Estimador PyTorch de SageMaker que ejecuta el script de entrenamiento, eval_linear.py. Los hiperparámetros de entrenamiento incluyen los detalles de la arquitectura del modelo DINO y la ruta del archivo para el punto de control del modelo:

# cubo de salida donde se cargan los artefactos finales del modelo
CLASSIFIER_OUTPUT_BUCKET = 'clasificacion-cobertura-suelo'

# nombre del punto de control de DINO
checkpoint = 'checkpoint.pth'

# rutas en la instancia de entrenamiento
sm_dino_path = f'/opt/ml/input/data/dino_checkpoint'          
sm_dino_checkpoint = f'{sm_dino_path}/{checkpoint}'           

# nombre del trabajo de entrenamiento
classifier_base_job_name = f'clasificador-lineal-{int(time.time())}'

# crear Estimador 
estimator = PyTorch(
    base_job_name=classifier_base_job_name,
    source_dir='ruta/a/aerial_featurizer',
    entry_point = 'eval_linear.py',
    role=role,
    framework_version='1.12',
    py_version='py38',
    instance_count=1,
    instance_type='ml.p3.2xlarge',
    sagemaker_session=sagemaker_session,
    hyperparameters = {
    # hiperparámetros pasados al script de punto de entrada
        'arch': 'vit_small',
        'pretrained_weights': sm_dino_checkpoint,
        'epochs': 50,
        'data_dir': sm_data_path,
        'metadata_dir': sm_metadata_path,
        'output_dir': sm_checkpoint_path,
        'num_labels': 19,
    },
    max_run=1*60*60, 
    checkpoint_local_path = sm_checkpoint_path,
    checkpoint_s3_uri =f's3://{CLASSIFIER_OUTPUT_BUCKET}/checkpoints/{base_job_name}',
)

Comenzamos el trabajo de entrenamiento utilizando el método fit, suministrando las ubicaciones de Amazon S3 del metadato de BigEarthNet-S2 y las imágenes de entrenamiento y el punto de control del modelo DINO:

# llamar a fit para comenzar el entrenamiento
estimator.fit(
    inputs={
    'metadata': 's3://bigearthnet-s2-dataset/metadata/',
    'dataset': 's3://bigearthnet-s2-dataset/data_rgb/',
    'dino_checkpoint': f's3://bigearthnet-s2-dataset/dino-models/checkpoints/{dino_base_job_name}',
    },
    wait=False
)

Cuando el entrenamiento esté completo, podemos realizar inferencias en el conjunto de pruebas de BigEarthNet-S2 utilizando SageMaker transformación por lotes o SageMaker Procesamiento. En la siguiente tabla, comparamos la precisión promedio del modelo lineal en imágenes del conjunto de pruebas usando dos representaciones de imágenes DINO diferentes. El primer modelo, ViT-S/16 (ImageNet), es el punto de control pequeño del transformador de visión incluido en el repositorio de DINO que fue pre-entrenado utilizando imágenes frontales en el conjunto de datos de ImageNet. El segundo modelo, ViT-S/16 (BigEarthNet-S2), es el modelo que producimos pre-entrenando en imágenes aéreas.

Modelo Precisión promedio
ViT-S/16 (ImageNet) 0.685
ViT-S/16 (BigEarthNet-S2) 0.732

Encontramos que el modelo DINO pre-entrenado en BigEarthNet-S2 se transfiere mejor a la tarea de clasificación de cobertura terrestre que el modelo DINO pre-entrenado en ImageNet, lo que resulta en un aumento del 6.7% en la precisión promedio.

Limpieza

Después de completar el entrenamiento y la transferencia de aprendizaje de DINO, podemos limpiar nuestros recursos para evitar incurrir en cargos. Detenemos o eliminamos nuestra instancia de notebook y eliminamos cualquier dato o artefacto de modelo no deseado de Amazon S3.

Conclusion

Este post demostró cómo entrenar modelos DINO en imágenes aéreas utilizando SageMaker. Utilizamos Estimadores PyTorch de SageMaker y SMDDP para generar representaciones de imágenes de BigEarthNet-S2 sin la necesidad de etiquetas explícitas. Luego transferimos las características de DINO a una tarea de clasificación de imágenes, que consistió en predecir la clase de cobertura terrestre de las imágenes de BigEarthNet-S2. Para esta tarea, el pre-entrenamiento en imágenes satelitales produjo un aumento del 6.7% en la precisión promedio en comparación con el pre-entrenamiento en ImageNet.

Puedes utilizar esta solución como una plantilla para entrenar modelos DINO en conjuntos de datos de imágenes aéreas y satelitales a gran escala y sin etiquetas. Para obtener más información sobre DINO y cómo construir modelos en SageMaker, consulta los siguientes recursos:

  • Emerging Properties in Self-Supervised Vision Transformers
  • Usar PyTorch con Amazon SageMaker
  • Librería de Paralelismo de Datos de SageMaker

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Rastreador web de OpenAI y errores de la FTC

OpenAI lanza un rastreador predeterminado de opt-in para raspar Internet, mientras que la FTC lleva a cabo una invest...

Inteligencia Artificial

La minería de Bitcoin utilizó más agua que la ciudad de Nueva York el año pasado.

Un estudio encontró que el uso de agua por parte de los mineros de bitcoin alcanzó los 591 mil millones de galones ha...

Inteligencia Artificial

OpenAI contempla unirse a la Liga de la fabricación de chips de IA

OpenAI, el gigante detrás del reconocido ChatGPT, podría adentrarse pronto en el dinámico mundo de la fabricación de ...

Inteligencia Artificial

Este documento de IA muestra cómo la toxicidad de ChatGPT puede aumentar hasta seis veces cuando se le asigna una personalidad

Con los avances tecnológicos recientes, los modelos de lenguaje grandes (LLMs) como GPT-3 y PaLM han mostrado habilid...

Inteligencia Artificial

Las 50 mejores herramientas de escritura de IA para probar (septiembre de 2023)

Grammarly Grammarly es una excelente herramienta para mejorar la escritura. Revisa la gramática, ortografía, puntuaci...