Downloads · 30 days
0
pierreadorni/eos-fm
eos-fm is a machine learning model from pierreadorni. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as cc-by-sa-4.0.
Pierre Adorni, Minh-Tan Pham, Stéphane May, Sébastien Lefèvre
Downloads · 30 days
0
Access
Public
Updated Dec 5, 2025
Repo size
319 MB
Likes
0
Public
Click a slice to open those files.
.pth286 MB · 100%
From the Hugging Face model README
Pierre Adorni, Minh-Tan Pham, Stéphane May, Sébastien Lefèvre
<div style="display: flex; gap:10px;"> <div style="transform: translateY(-13px)"> </div> </div> <p align='center'> <img src="https://github.com/user-attachments/assets/8a4e9f7f-6fdf-42f3-a4b7-879343024962" width="100%"/> </p>An ensemble foundation model for Earth Observation that aggregates features from multiple specialist backbone encoders to achieve generalist capabilities across diverse remote sensing tasks.
EoS-FM addresses a fundamental question in remote sensing foundation models: rather than training a single large generalist model on massive amounts of data, can we ensemble multiple specialist models trained on different tasks and band combinations to achieve comparable or better generalist performance?
The EosFM encoder implements a late fusion ensemble approach:
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install dependencies
pip install -e .
# Install additional dependencies (adjust based on your needs)
pip install terratorch torchgeo lightning rasterio torch torchvision
# Set up environment
source venv/bin/activate
export PYTHONPATH=$(pwd):$PYTHONPATH
# Train on a dataset (e.g., Cloud Cover)
python run.py experiment=train/cloud_cover
# List all available experiments
python run.py --help | grep "experiment"
# Available experiments: ben_rgb, ben_s1, ben_all, caffe, cloud_cover, deepglobe_lcc,
# dfc2022, dior, etci2021, eurosat_rgb, eurosat_s2, firerisk, inria_aerial,
# kenya_croptype, landcoverai, levircdplus, loveda, minifrance, opencanopy, oscd,
# potsdam, sen12ms_rgb, sen12ms_s1, sen12ms_s2, sen12ms_all
# Check that configuration is valid without training
python run.py experiment=train/potsdam train=false
# Example: in conf/experiment/my_experiment.yaml
defaults:
- override /model: segmentation
data:
_target_: eosfm.datamodules.MyDataModule
batch_size: 32
num_workers: 8
root: /path/to/data
trainer:
max_epochs: 100
accelerator: auto
devices: auto
precision: bf16-mixed
logger:
name: my_experiment
model:
model_args:
backbone: EosFM
backbone_in_chans: 3
model_weights: models/eosfm.pth
freeze: true # Freeze encoders during training (recommended)
num_classes: 6
loss: dice
1. Basic Concatenation (Default)
model:
model_args:
backbone: EosFM
num_classes: 6
2. Encoder Selection with Top-K
model:
model_args:
backbone: EosFM
max_encoders: 5 # Select only 5 most relevant encoders
num_classes: 6
3. Feature Normalization
model:
model_args:
backbone: EosFM
normalize_features: true
normalization_type: "batch" # "batch" or "layer"
num_classes: 6
The ensemble file format is a list of tuples: [(in_chans, state_dict, config), ...]
The utils.py script provides utilities to load and export ensemble models from a folder of trained Lightning checkpoints:
# Export all trained models from an experiments folder to an ensemble .pth file
python utils.py export \
--encoders-folder experiments/train \
--output-path eosfm_ensemble.pth
This command:
experiments/trainCustom datamodules in eosfm/datamodules/:
Also supports TorchGeo datasets: EuroSAT, DeepGlobe, FireRisk, OSCD, etc.
class MyDataModule(PinNonGeoDataModule):
def setup(self, stage):
if stage in ['fit', 'validate']:
self.train_dataset = MyDataset(use_tiling=False) # Random crops
self.val_dataset = MyDataset(use_tiling=True) # Systematic tiling
Configurations use Hydra for composable, modular setup. Each experiment is self-contained with data, model, and trainer configurations.
Each experiment is a minimal YAML file that specifies data, model, and training settings:
# config/experiment/train/cloud_cover.yaml
# @package _global_
defaults:
- override /model: segmentation
data:
_target_: eosfm.datamodules.CloudCoverDetectionDataModule
batch_size: 32
num_workers: 4
root: data/cloud_cover
trainer:
max_epochs: 20
check_val_every_n_epoch: 1
logger:
name: cloud_cover
model:
model_args:
num_classes: 2
loss: ce
config/experiment/train/:# config/experiment/train/my_dataset.yaml
# @package _global_
defaults:
- override /model: segmentation
data:
_target_: my.custom.DataModule
batch_size: 32
num_workers: 8
root: /path/to/data
trainer:
max_epochs: 100
logger:
name: my_dataset
model:
model_args:
num_classes: 10
backbone: timm_convnextv2_atto
loss: dice
python run.py experiment=train/my_dataset
# Or override specific settings from CLI:
python run.py experiment=train/my_dataset trainer.max_epochs=50 data.batch_size=64
Override any configuration value from the command line:
# Override epochs, batch size, learning rate
python run.py experiment=train/potsdam trainer.max_epochs=200 data.batch_size=16
# Disable training, only validate
python run.py experiment=train/potsdam train=false
# Run a dry run to verify configuration
python run.py experiment=train/potsdam train=false test=false --cfg job
Training automatically tracks CO₂ emissions via CodeCarbon. The energy consumption and estimated CO₂eq for this project are detailed below. Note that these are not the values for a single training of the model, but rather for all of the trial and error runs during the project, up to the final full training run.
| Total emissions | Total energy consumed |
|---|---|
| 4.15 kg CO₂eq | 76.05 kWh |
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Contributions welcome! Please:
@article{adorni2025eos,
title={EoS-FM: Can an Ensemble of Specialist Models act as a Generalist Feature Extractor?},
author={Adorni, Pierre and Pham, Minh-Tan and May, St{\'e}phane and Lef{\`e}vre, S{\'e}bastien},
journal={arXiv preprint arXiv:2511.21523},
year={2025}
}