CoolFace
Modelpublic

Dnyanesh29/segformer-b2-desert

sourceHugging Faceapache-2.0updated 6mo agoView on Hugging Face
0likes4downloads
Model Card

๐ŸŒต SegFormer-B2 โ€” Offroad Desert Semantic Segmentation

YOLO Pune Hackathon 2026 ยท Duality AI ร— MIT WPU

Fine-tuned nvidia/mit-b2 on synthetic desert imagery from Duality AI's Falcon simulation platform. The model segments every pixel of a desert scene into one of 10 classes. It was trained on Desert A and evaluated on a completely unseen Desert B location โ€” a domain shift challenge.


๐Ÿ“Š Results

SplitmIoUNotes
Val (Desert A holdout)0.6293317 images, dedicated Duality AI split
Test (Desert B โ€” raw)0.28431002 images, different location
Test (Desert B โ€” corrected)0.40617 present classes only; Flowers, Logs, Ground Clutter absent in Desert B

Per-class IoU (Test Set โ€” Desert B)

ClassVal IoUTest IoUPresent in Desert B
๐ŸŒณ Trees0.85720.3896โœ…
๐ŸŒฟ Lush Bushes0.69370.0003โœ…
๐ŸŒพ Dry Grass0.69230.4502โœ…
๐Ÿชจ Dry Bushes0.49290.3831โœ…
๐ŸŒธ Flowers0.57570.0000โŒ Absent
๐Ÿชต Logs0.52140.0000โŒ Absent
โ›ฐ๏ธ Rocks0.48770.0402โœ…
๐Ÿœ๏ธ Landscape0.60070.5993โœ…
โ˜๏ธ Sky0.98390.9802โœ…
๐Ÿชจ Ground Clutter0.38740.0000โŒ Absent
Note on corrected mIoU: The 3 absent classes (Flowers, Logs, Ground Clutter) score IoU=0 by definition โ€” the model never sees them in the test set. Corrected mIoU averages only the 7 classes that actually appear in Desert B.

๐Ÿ—๏ธ Model Details

PropertyValue
ArchitectureSegFormer-B2 (Mix-Transformer encoder + All-MLP decoder)
Base modelnvidia/mit-b2 (ImageNet-1K pretrained)
Total parameters27.4M
Encoder23.7M (pretrained)
Decoder head3.7M (randomly initialised, fine-tuned)
Input resolution512 ร— 512 px
Output classes10
Training platformKaggle GPU (T4/P100)

๐Ÿ—‚๏ธ Dataset

Synthetic desert images generated by Duality AI's Falcon simulation platform.

SplitImagesMasksLocation
Train2,8572,857Desert A
Val317317Desert A (dedicated split)
Test1,0021,002Desert B (unseen)

Mask label IDs โ€” non-standard sparse integers remapped to 0โ€“9:

Raw IDClassCompact ID
100Trees0
200Lush Bushes1
300Dry Grass2
500Dry Bushes3
550Ground Clutter4
600Flowers โš‘ rare5
700Logs โš‘ rare6
800Rocks7
7100Landscape8
10000Sky9

โš™๏ธ Training Configuration

Optimiser & Schedule

Optimiser   : AdamW   lr=6e-5   weight_decay=1e-2
LR schedule : CosineAnnealingLR   T_max=50   eta_min=1e-7
Grad clip   : max_norm=1.0
Early stop  : patience=7 epochs on val mIoU
Best epoch  : 19   (V2 model)

Loss Function

Weighted CrossEntropyLoss with ignore_index=255 to handle unlabelled pixels.

ClassWeightReason
Flowers5.0ร—Extremely rare โ€” forces model to notice them
Logs4.0ร—Rare and often partially occluded
Ground Clutter2.0ร—Small objects, easily missed
Lush Bushes, Dry Bushes2.0ร—Medium frequency
Trees, Dry Grass, Rocks1.5ร—Moderate
Sky0.8ร—Dominant โ€” downweighted
Landscape0.5ร—Most dominant โ€” heavily downweighted

Augmentation Pipeline

All four techniques recommended in Duality AI's official training guide:

python
A.Resize(512, 512),
A.HorizontalFlip(p=0.5),                         # 1. Flip โ€” deserts have no L/R bias
A.RandomResizedCrop(size=(512,512),               # 2. Zoom โ€” simulates camera distance
    scale=(0.6, 1.0), ratio=(0.75, 1.33), p=0.5),
A.Affine(shear=(-15,15), rotate=(-10,10), p=0.4), # 3. Shear โ€” off-level camera angles
# 4. Mosaic โ€” 4 images stitched into 2ร—2 grid (30% probability, custom implementation)
A.HueSaturationValue(                             # 5. HSV โ€” MILD to preserve warm desert palette
    hue_shift_limit=10, sat_shift_limit=20,
    val_shift_limit=15, p=0.4),
A.RandomBrightnessContrast(
    brightness_limit=0.15, contrast_limit=0.15, p=0.4),
A.Normalize(mean=[0.485,0.456,0.406], std=[0.229,0.224,0.225]),
โš ๏ธ HSV jitter is intentionally mild. The Duality AI desert palette is warm-toned. Aggressive colour shifts would train the model on unrealistic lighting and hurt generalisation.

๐Ÿš€ Usage

Quick inference

python
import torch
import numpy as np
from PIL import Image
from transformers import SegformerForSemanticSegmentation
import albumentations as A
from albumentations.pytorch import ToTensorV2
import torch.nn.functional as F

# โ”€โ”€ Class definitions โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
CLASS_NAMES = [
    "Trees", "Lush_Bushes", "Dry_Grass", "Dry_Bushes",
    "Ground_Clutter", "Flowers", "Logs", "Rocks", "Landscape", "Sky"
]
PALETTE = np.array([
    [34,139,34],[0,200,83],[210,180,140],[200,200,180],[139,90,43],
    [255,20,147],[139,69,19],[128,128,128],[205,170,100],[135,206,235]
], dtype=np.uint8)

# โ”€โ”€ Load model โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model  = SegformerForSemanticSegmentation.from_pretrained(
    "YOUR_HF_USERNAME/segformer-b2-desert-segmentation"
).to(device).eval()

# โ”€โ”€ Preprocess โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
transform = A.Compose([
    A.Resize(512, 512),
    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ToTensorV2(),
])

# โ”€โ”€ Inference โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
img    = np.array(Image.open("desert_image.png").convert("RGB"))
h0, w0 = img.shape[:2]
tensor = transform(image=img)["image"].unsqueeze(0).to(device)

with torch.no_grad():
    logits = model(pixel_values=tensor).logits          # [1, 10, H/4, W/4]
    up     = F.interpolate(logits, size=(h0, w0),
                           mode="bilinear", align_corners=False)
    pred   = up.argmax(dim=1).squeeze(0).cpu().numpy()  # [H, W]  values 0โ€“9

# โ”€โ”€ Colour visualisation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
def mask_to_rgb(mask):
    rgb = np.zeros((*mask.shape, 3), dtype=np.uint8)
    for c in range(10):
        rgb[mask == c] = PALETTE[c]
    return rgb

pred_rgb = mask_to_rgb(pred)
Image.fromarray(pred_rgb).save("segmentation_output.png")
print("Classes found:", [CLASS_NAMES[c] for c in np.unique(pred)])

Load from checkpoint

python
import torch
from transformers import SegformerForSemanticSegmentation

# HuggingFace directory
model = SegformerForSemanticSegmentation.from_pretrained(
    "YOUR_HF_USERNAME/segformer-b2-desert-segmentation"
).eval()

# Raw .pth checkpoint (if you downloaded it separately)
ckpt = torch.load("best_model.pth", map_location="cpu")
model.load_state_dict(ckpt["model_state"])
print(f"Loaded epoch {ckpt['epoch']} โ€” val mIoU {ckpt['val_miou']:.4f}")

โš ๏ธ Limitations & Known Issues

  • โ€”Domain shift is real. The model was trained on Desert A (Duality AI Falcon synthetic data). Performance on real-world desert images or different Falcon biomes may vary significantly.
  • โ€”3 classes absent in Desert B. Flowers, Logs, and Ground Clutter do not appear in the test location. The model has learned to predict them on Desert A but will produce near-zero IoU on any location where they are absent.
  • โ€”Lush Bushes test generalisation is poor (IoU 0.6937 val โ†’ 0.0003 test). Desert B appears to have a very different bush distribution or colour tone from Desert A.
  • โ€”Rocks generalise weakly (0.4877 โ†’ 0.0402). Rock textures vary heavily between locations.
  • โ€”Sky and Landscape generalise near-perfectly (Sky: 0.9839 โ†’ 0.9802; Landscape: 0.6007 โ†’ 0.5993). These classes are visually consistent across desert biomes.

๐Ÿ“ Repository Structure

segformer-b2-desert-segmentation/
โ”œโ”€โ”€ config.json                  โ† model architecture config
โ”œโ”€โ”€ model.safetensors            โ† fine-tuned weights (404 MB)
โ”œโ”€โ”€ preprocessor_config.json     โ† image processor settings
โ”œโ”€โ”€ metadata.json                โ† training metadata & scores
โ””โ”€โ”€ README.md                    โ† this file

๐Ÿ“š Citation

If you use this model, please cite:

bibtex
@misc{mitwpu2025desert,
  title        = {SegFormer-B2 Fine-tuned on Duality AI Desert Segmentation},
  author       = {MIT WPU Team},
  year         = {2025},
  howpublished = {YOLO Pune Hackathon 2025, Duality AI Challenge},
  url          = {https://huggingface.co/YOUR_HF_USERNAME/segformer-b2-desert-segmentation}
}

Base model:

bibtex
@article{xie2021segformer,
  title   = {SegFormer: Simple and Efficient Design for Semantic Segmentation with Transformers},
  author  = {Xie, Enze and Wang, Wenhai and Yu, Zhiding and Anandkumar, Anima and Alvarez, Jose M and Luo, Ping},
  journal = {NeurIPS},
  year    = {2021}
}

๐Ÿ… Acknowledgements

  • โ€”Duality AI for the Falcon synthetic dataset and challenge
  • โ€”NVIDIA for the pretrained SegFormer-B2 backbone
  • โ€”YOLO Pune Hackathon 2025 organisers at MIT WPU

Model trained and evaluated by MIT WPU for the Duality AI Offroad Segmentation challenge at YOLO Pune Hackathon 2026.