DOFA (dofa)¶
DOFA adapter for multispectral inputs with explicit per-channel wavelengths, supporting provider and tensor backends.
Quick Facts¶
| Field | Value |
|---|---|
| Model ID | dofa |
| Family / Backbone | DOFA ViT (base / large, official checkpoints) |
| Adapter type | on-the-fly |
| Typical backend | provider backend (gee), also supports backend="tensor" |
| Primary input | Raw Sentinel-2 SR CHW + wavelengths (µm) |
| Default resolution | 10m default provider fetch (sensor.scale_m) |
| Temporal mode | provider path requires TemporalSpec.range(...) |
| Output modes | pooled, grid |
| Model config keys | variant (default: base; choices: base, large) |
| Extra side inputs | required wavelength vector (wavelengths_um) |
| Training alignment (adapter path) | Medium-High (when wavelengths and band semantics are correct) |
When To Use This Model¶
DOFA is the right choice when wavelength-aware multispectral modeling matters, when you need custom band combinations with matching wavelengths, or when you want to compare spectral models against more S2-specific adapters. The main failure mode is semantic mismatch: missing wavelengths, wrong wavelength-to-channel alignment, or unlogged changes to variant and wavelength configuration will all make results hard to trust.
Input Contract (Current Adapter Path)¶
Spatial / temporal¶
The provider path requires TemporalSpec.range(start, end). The tensor path bypasses provider fetch entirely, so temporal semantics only matter insofar as they shaped the tensor you prepared.
Sensor / channels (provider path)¶
If sensor is omitted, the provider path uses COPERNICUS/S2_SR_HARMONIZED with the official DOFA S2 9-band order B4,B3,B2,B5,B6,B7,B8,B11,B12, plus scale_m=10, cloudy_pct=30, composite="median", and fill_value=0.0.
Wavelengths:
The adapter requires one wavelength in micrometers per channel. If sensor.wavelengths is not provided, it tries to infer wavelengths from sensor.bands, but only known schemas such as the supported Sentinel-2 subsets are inferable. len(wavelengths_um) must always match the channel count C.
input_chw contract (provider override path):
If you override fetch with input_chw, it must be CHW with C == len(bands) and raw SR values in 0..10000.
Tensor backend contract¶
For backend="tensor", input_chw must be CHW, and batch tensor usage should go through get_embeddings_batch_from_inputs(...). sensor.bands is required so the official preprocessing path can be applied, and sensor.wavelengths should either be provided directly or be inferable from the bands. The tensor is expected to hold raw SR values in 0..10000, not pre-normalized [0,1].
Preprocessing Pipeline (Current rs-embed Path)¶
Provider path¶
PROVIDER fetch raw multiband Sentinel-2 SR patch
-> optional raw-value inspection
expected_channels=len(bands), value range [0,10000]
-> raw SR 0..10000 -> 0..255-like scale
-> official DOFA S2 per-band mean/std normalization
-> resize to fixed 224x224
bilinear; no crop / pad
-> load DOFA model variant
variant: base | large
-> forward(image, wavelengths)
-> output projection
pooled: embedding vector
grid: patch-token grid
Tensor path¶
TENSOR read raw SR input_chw
-> reject already-normalized [0,1]-like inputs
-> apply provider-equivalent DOFA preprocessing
raw SR 0..10000 -> [0,1]
rescale to 0..255-like values
official per-band mean/std normalization
-> resize to fixed 224x224
-> resolve wavelengths
preferred: sensor.wavelengths
fallback: infer from sensor.bands
-> forward(image, wavelengths)
-> output projection
pooled: embedding vector
grid: patch-token grid
Fixed adapter behavior:
The current implementation fixes image size at 224, and the official preprocessing path is defined for Sentinel-2 subsets of B4,B3,B2,B5,B6,B7,B8,B11,B12.
Environment Variables / Tuning Knobs¶
| Env var | Default | Effect |
|---|---|---|
RS_EMBED_DOFA_FETCH_WORKERS |
8 |
Provider prefetch workers for batch APIs |
RS_EMBED_DOFA_BATCH_SIZE |
CPU:8, CUDA:64 |
Inference batch size for batch APIs |
RS_EMBED_DOFA_BASE_WEIGHTS |
unset | Local override for the base checkpoint file |
RS_EMBED_DOFA_LARGE_WEIGHTS |
unset | Local override for the large checkpoint file |
RS_EMBED_DOFA_WEIGHTS_DIR |
unset | Directory override containing DOFA checkpoint files |
RS_EMBED_DOFA_HF_REPO_ID |
earthflow/DOFA |
Hugging Face repo used for checkpoint download |
RS_EMBED_DOFA_HF_REVISION |
main |
Hugging Face revision used for checkpoint download |
Non-env model selection knobs:
The main non-env knobs are variant (base or large), sensor.bands for channel semantics and wavelength inference, and sensor.wavelengths for an explicit wavelength vector in micrometers.
If variant is omitted, rs-embed uses the base DOFA checkpoint by default. Pass variant="large" to switch to the larger model.
Quick reminder:
Pass variant directly to get_embedding("dofa", ..., variant="base"). For export jobs, use ExportModelRequest.configure("dofa", variant="large").
Output Semantics¶
DOFA mostly follows the standard pooled and token-grid pattern. pooled returns a vector (D,), while grid reshapes patch tokens to (D,H,W) in model token space rather than georeferenced raster space. The model-specific part is mainly in metadata, which records wavelengths, variant choice, and preprocessing details.
Examples¶
Minimal provider-backed example (S2 wavelengths inferred automatically)¶
from rs_embed import get_embedding, PointBuffer, TemporalSpec, OutputSpec
emb = get_embedding(
"dofa",
spatial=PointBuffer(lon=121.5, lat=31.2, buffer_m=2048),
temporal=TemporalSpec.range("2022-06-01", "2022-09-01"),
output=OutputSpec.pooled(),
backend="gee",
)
Switch to the large checkpoint¶
from rs_embed import get_embedding, PointBuffer, TemporalSpec, OutputSpec
emb = get_embedding(
"dofa",
spatial=PointBuffer(lon=121.5, lat=31.2, buffer_m=2048),
temporal=TemporalSpec.range("2022-06-01", "2022-09-01"),
output=OutputSpec.pooled(),
backend="gee",
variant="large",
)
Custom bands / wavelengths example (conceptual)¶
from rs_embed import SensorSpec
sensor = SensorSpec(
collection="COPERNICUS/S2_SR_HARMONIZED",
bands=("B2", "B3", "B4", "B8"),
scale_m=10,
)
# If bands are non-standard, provide wavelengths explicitly via an extended sensor object/field used by your code path.
Common Failure Modes / Debugging¶
- provider path called with non-
rangetemporal spec - wavelength vector missing or wrong length for channel count
- unsupported bands for the official S2 preprocessing path
- tensor backend called with already-normalized
[0,1]inputs - tensor backend called without
input_chw - unknown
variant(must bebaseorlarge)
Recommended first checks:
Print or log the exact bands and wavelengths_um used by the adapter, then verify that the provider or tensor input is scaled and ordered the way you intended before blaming the model.
Reproducibility Notes¶
Keep the variant, exact bands, exact wavelengths_um, temporal window and compositing policy, output mode, and backend choice fixed and recorded. Those settings materially change what DOFA sees.
Source of Truth (Code Pointers)¶
The main code paths are src/rs_embed/embedders/catalog.py for registration and src/rs_embed/embedders/onthefly_dofa.py for both adapter logic and wavelength inference.