SatlasPretrain Models

repository·main·Indexed 41 days ago

https://github.com/allenai/satlaspretrain_models

A lightweight library providing foundation models pretrained on large-scale remote sensing datasets, including Sentinel-1, Sentinel-2, Landsat, and high-resolution aerial imagery. These models serve as backbones or feature extractors for downstream satellite imagery tasks such as classification, segmentation, and detection. The library supports single-image (SI) and multi-image (MI) configurations and provides tools for attaching task-specific heads via satlaspretrain_models.Head.

Tokens
3K
Snippets
8
Records
12
Agent score
100%

What's inside SatlasPretrain Models

  1. How SatlasPretrain models are structured

    main

    SatlasPretrain models consist of three main components:

    1. Backbone: Extracts features from input images.
    2. Feature Pyramid Network (FPN): Provides multi-scale feature maps.
    3. Prediction Head: Task-specific output layer (e.g., classification, segmentation).

    Single-image vs. Multi-image models:

    • Single-image (SI) models: Input an individual image.
    • Multi-image (MI) models: Input multiple aligned images. The backbone is applied to each individual image, and then max pooling is applied across the temporal dimension (the multiple images) to create a robust representation.
  2. Normalize input data for Landsat 8/9

    main

    For Landsat models, normalize the 16-bit B1-B11 bands using the following formula:

    # landsat_images is a stack of bands
    tensor = torch.clip((landsat_images[None, :, :, :, :] - 4000) / 16320, 0, 1)
    # landsat_images = torch.stack([landsat_image1, landsat_image2], dim=0)
    # tensor = torch.clip(landsat_images[None, :, :, :, :]-4000)/16320, 0, 1)
  3. Normalize input data for Sentinel-2 and Sentinel-1

    main

    Input tensors must be normalized according to the sensor type:

    Sentinel-2 L1C TCI (RGB): Divide 0-255 pixel values by 255 to scale to 0-1.

    tensor = tci_image[None, :, :, :] / 255

    Sentinel-1 (VH+VV): Divide 16-bit pixel values by 255 and clip to the 0-1 range.

    tensor = torch.clip(torch.stack([vh_image, vv_image], dim=0)[None, :, :, :] / 255, 0, 1)
  4. Install satlaspretrain-models via conda and pip

    main

    To install the library, create a new conda environment with Python 3.9 and install the package using pip.

    conda create --name satlaspretrain python==3.9
    conda activate satlaspretrain
    pip install satlaspretrain-models
  5. Setup a dedicated environment for the Torchgeo demo

    main

    The Torchgeo demo requires a separate conda environment from the standard SatlasPretrain demo. Follow these steps to create and configure the environment:

    1. Create a new conda environment with Python 3.12.
    2. Activate the environment.
    3. Install torchgeo directly from GitHub (as Satlas weights are scheduled for the 0.6.0 release and the current version is 0.5.1).
    conda create --name torchgeodemo python=3.12
    conda activate torchgeodemo
    pip install git+https://github.com/microsoft/torchgeo
  6. Fine-tune SatlasPretrain models using Torchgeo ClassificationTask

    main

    To fine-tune a SatlasPretrain model on a custom dataset (like UCMerced) using Torchgeo, you should extend the ClassificationTask class.

    In the configure_models method, you must:

    1. Load the model using swin_v2_b with the Swin_V2_B_Weights.SENTINEL2_RGB_SI_SATLAS weights.
    2. Adjust the first layer's input channels to match your task's input requirements.
    3. Replace the model's head with a new torch.nn.Linear layer that matches your number of classes.

    Example implementation:

    from torchgeo.trainers import ClassificationTask
    from torchgeo.models import Swin_V2_B_Weights, swin_v2_b
    import torch
    
    class SatlasClassificationTask(ClassificationTask):
        def configure_models(self):
            # Load pretrained Satlas weights
            weights = Swin_V2_B_Weights.SENTINEL2_RGB_SI_SATLAS
            self.model = swin_v2_b(weights)
    
            # Replace first layer's input channels
            first_layer = self.model.features[0][0]
            self.model.features[0][0] = torch.nn.Conv2d(
                3, # Number of input channels
                first_layer.out_channels,
                kernel_size=first_layer.kernel_size,
                stride=first_layer.stride,
                padding=first_layer.padding,
                bias=(first_layer.bias is not None)
            )
    
            # Replace last layer's output features with the number of classes
            self.model.head = torch.nn.Linear(
                in_features=1024, 
                out_features=self.hparams["num_classes"],
                bias=True
            )
    
        def on_validation_epoch_end(self):
            # Accessing metrics logged during the current validation epoch
            val_loss = self.trainer.callback_metrics.get('val_loss', 'N/A')
            val_acc = self.trainer.callback_metrics.get('val_OverallAccuracy', 'N/A')
            print(f"Epoch {self.current_epoch} Validation - Loss: {val_loss}, Accuracy: {val_acc}")
    
    # Usage
    task = SatlasClassificationTask(num_classes=21)
    class SatlasClassificationTask(ClassificationTask):
        def configure_models(self):
            weights = Swin_V2_B_Weights.SENTINEL2_RGB_SI_SATLAS
            self.model = swin_v2_b(weights)
    
            first_layer = self.model.features[0][0]
            self.model.features[0][0] = torch.nn.Conv2d(3,
                                        first_layer.out_channels,
                                        kernel_size=first_layer.kernel_size,
                                        stride=first_layer.stride,
                                        padding=first_layer.padding,
                                        bias=(first_layer.bias is not None))
    
            self.model.head = torch.nn.Linear(in_features=1024, out_features=self.hparams["num_classes"], bias=True)
  7. Fine-tune a SatlasPretrain Sentinel-2 model for classification

    main

    This guide demonstrates how to fine-tune a Sentinel2_SwinB_SI_RGB model using the EuroSAT classification task. The process involves downloading the dataset, preparing a PyTorch Dataset and DataLoader, initializing the pretrained model with a classification head, and running a standard training loop.

    Model Initialization

    To use the model for classification, use the Weights manager to load the backbone with a specific head configuration. For EuroSAT, you should set num_categories=10 and use satlaspretrain_models.Head.CLASSIFY.

    Data Preprocessing Requirements

    When using Sentinel-2 TCI images, ensure the input is normalized: pixel values (0-255) must be divided by 255 to scale them to the 0-1 range.

    import satlaspretrain_models
    import torch
    
    weights_manager = satlaspretrain_models.Weights()
    model = weights_manager.get_pretrained_model(
        "Sentinel2_SwinB_SI_RGB", 
        fpn=True, 
        head=satlaspretrain_models.Head.CLASSIFY, 
        num_categories=10, 
        device='cpu'
    )
    model = model.to('cpu')
  8. Load pretrained models using Weights.get_pretrained_model()

    main

    To use the models, first initialize a satlaspretrain_models.Weights instance. You can then load either the backbone or the backbone+FPN by providing a model_identifier (checkpoint ID).

    import satlaspretrain_models
    import torch
    
    weights_manager = satlaspretrain_models.Weights()
    
    # Load backbone only
    model = weights_manager.get_pretrained_model("Sentinel2_SwinB_SI_RGB")
    
    # Load backbone + FPN
    model = weights_manager.get_pretrained_model("Sentinel2_SwinB_SI_RGB", fpn=True)
    import satlaspretrain_models
    import torch
    
    weights_manager = satlaspretrain_models.Weights()
    MODEL_CHECKPOINT_ID = "Sentinel2_SwinB_SI_RGB"
    model = weights_manager.get_pretrained_model(MODEL_CHECKPOINT_ID)
    model = weights_manager.get_pretrained_model(MODEL_CHECKPOINT_ID, fpn=True)
  9. Attach task-specific heads for fine-tuning

    main

    While the repository does not support loading pretrained prediction heads (as they are task-specific), you can attach randomly initialized heads to the backbone or FPN to facilitate fine-tuning. Use the head and num_categories arguments in get_pretrained_model().

    Available Head Architectures (satlaspretrain_models.Head):

    • Segmentation: U-Net Decoder w/ Cross Entropy loss
    • Detection: Faster R-CNN Decoder
    • Instance Segmentation: Mask R-CNN Decoder
    • Regression: U-Net Decoder w/ L1 loss
    • Classification: Pooling + Linear layers
    • Multi-label Classification: Pooling + Linear layers

    Example: Attaching a classification head:

    model = weights_manager.get_pretrained_model(
        "Aerial_SwinB_MI", 
        fpn=True, 
        head=satlaspretrain_models.Head.CLASSIFY, 
        num_categories=2
    )
    # Backbone and FPN parameters initialized from checkpoint, head parameters initialized randomly.
    model = weights_manager.get_pretrained_model(MODEL_CHECKPOINT_ID, fpn=True, head=satlaspretrain_models.Head.CLASSIFY, num_categories=2)
  10. Available model checkpoint IDs

    main

    Use these identifiers with weights_manager.get_pretrained_model() to load specific pretrained weights. Checkpoints are categorized by sensor type, image mode (Single-image vs Multi-image), and spectral configuration.

    Sentinel-2

    • Swin-v2-Base (RGB): Sentinel2_SwinB_SI_RGB (SI), Sentinel2_SwinB_MI_RGB (MI)
    • Swin-v2-Tiny (RGB): Sentinel2_SwinT_SI_RGB (SI), Sentinel2_SwinT_MI_RGB (MI)
    • Resnet50 (RGB): Sentinel2_Resnet50_SI_RGB (SI), Sentinel2_Resnet50_MI_RGB (MI)
    • Resnet152 (RGB): Sentinel2_Resnet152_SI_RGB (SI), Sentinel2_Resnet152_MI_RGB (MI)
    • Swin-v2-Base (MS - 9 bands): Sentinel2_SwinB_SI_MS (SI), Sentinel2_SwinB_MI_MS (MI)
    • Swin-v2-Tiny (MS - 9 bands): Sentinel2_SwinT_SI_MS (SI), Sentinel2_SwinT_MI_MS (MI)
    • Resnet50 (MS - 9 bands): Sentinel2_Resnet50_SI_MS (SI), Sentinel2_Resnet50_MI_MS (MI)
    • Resnet152 (MS - 9 bands): Sentinel2_Resnet152_SI_MS (SI), Sentinel2_Resnet152_MI_MS (MI)

    Sentinel-1 (VH+VV)

    • Swin-v2-Base: Sentinel1_SwinB_SI (SI), Sentinel1_SwinB_MI (MI)

    Landsat 8/9 (All bands)

    • Swin-v2-Base: Landsat_SwinB_SI (SI), Landsat_SwinB_MI (MI)

    Aerial (0.5-2m/px RGB)

    • Swin-v2-Base: Aerial_SwinB_SI (SI), Aerial_SwinB_MI (MI)
  11. Initialize pretrained models with Weights.get_pretrained_model()

    main

    The satlaspretrain_models.Weights().get_pretrained_model() method is used to instantiate a model with specific pretrained weights and architectural components.

    Parameters:

    • model_name (str): The identifier for the pretrained weights (e.g., "Sentinel2_SwinB_SI_RGB").
    • fpn (bool): Whether to include a Feature Pyramid Network.
    • head (satlaspretrain_models.Head): The type of task head to attach (e.g., satlaspretrain_models.Head.CLASSIFY).
    • num_categories (int): The number of output classes for the head.
    • device (str): The device to load the model onto (e.g., 'cpu' or 'cuda').
    weights_manager = satlaspretrain_models.Weights()
    model = weights_manager.get_pretrained_model("Sentinel2_SwinB_SI_RGB", fpn=True, head=satlaspretrain_models.Head.CLASSIFY, num_categories=10, device='cpu')