Install · Quickstart · Gallery · Tutorials · Models · Docs · Cite
Earth Embedding returns embeddings, with their provenance, from three kinds of Earth representation models through one Python interface. Choose a place, a time window and an output, then swap the model name:
from earth_embedding import PointBuffer, TemporalSpec, OutputSpec, get_embedding
spatial = PointBuffer(lon=114.41, lat=30.52, buffer_m=640)
temporal = TemporalSpec.range("2021-05-01", "2021-10-31")
emb = get_embedding("prithvi", spatial=spatial, temporal=temporal, output=OutputSpec.grid())
gle = get_embedding("esri_gle", spatial=spatial, output=OutputSpec.grid(), grid_step_m=80)| Image encoders · 16 | Location encoders · 3 | Precomputed products · 3 |
|---|---|---|
| Imagery + time window → features. RemoteCLIP, SatMAE, Prithvi-EO-2.0, TerraMind, DOFA, THOR, Galileo, AnySat and more. | Longitude, latitude → features, on CPU and without imagery. SatCLIP, GeoCLIP, Esri GLE. | Read published embeddings. AlphaEarth / Google Satellite Embedding (also straight from GCS), TESSERA, Copernicus-Embed. |
- One geographic API:
get_embedding,compare_embeddingsand batch export share the samespatial/temporal/outputspecs. - Real, checked examples: bundled SHA-256-verified Bay Area data run offline on a laptop CPU.
- Explicit contracts: every result carries
.dataand.meta(model, source, dates, preprocessing), and differences in spatial support are never hidden. - Compatible: existing
rs_embedimports and thers-embedcommand keep working.
Origin. Earth Embedding is an independently maintained extension of CyberGIS rs-embed by Dingqi Ye and contributors, keeping its Apache-2.0 license, APIs and adapters. See origin and attribution.
Python 3.12+. Install from this repository (no PyPI release is assumed):
python -m pip install "earth-embedding @ git+https://github.com/GISWLH/earth-embedding.git"For the tutorials, optional integrations or development, clone and add extras:
git clone https://github.com/GISWLH/earth-embedding.git
cd earth-embedding
python -m pip install -e ".[demo,location,aef]"Optional extras and Earth Engine setup
| Extra | When you need it |
|---|---|
.[demo] |
Plotting, linear probes and executing the guided notebooks |
.[location] |
GeoCLIP's official package; SatCLIP and Esri GLE use bundled runtimes |
.[aef] |
Rasterio and PyArrow for direct AlphaEarth COG sampling and Parquet indexes |
.[benchmark] |
Scikit-learn and SciPy for the spatial-holdout evaluation example |
.[terratorch] |
TerraMind's TerraTorch runtime; Prithvi uses a bundled runtime |
.[dev,full,location,aef,benchmark] |
Development checks and all optional integrations |
Install PyTorch for your hardware. Weights download on first use; large image encoders need substantial memory. Inspecting the catalog runs no inference:
earth-embedding models --json
earth-embedding describe satclipImage and product routes that use Earth Engine need earthengine authenticate and an
eligible Cloud project (EE_PROJECT when required). Location encoders and direct
AlphaEarth GCS sampling do not initialize Earth Engine.
No imagery or date. Inputs are WGS84 degrees in [longitude, latitude] order.
from earth_embedding import get_location_embeddings
locations = [[-122.42, 37.77], [139.76, 35.68], [-0.12, 51.51]]
satclip = get_location_embeddings("satclip", locations, device="cpu") # (3, 256)
esri = get_location_embeddings("esri_gle", locations, device="cpu") # (3, 256), ~3.7 MB weights
geoclip = get_location_embeddings("geoclip", locations, device="cpu") # (3, 512), needs .[location]
print(satclip.data.shape, satclip.meta)Esri GLE runs its official weights directly in PyTorch: no ArcGIS or ArcPy. Downloads
are pinned by SHA-256, and a local .dlpk or satclip.pth works offline; Esri's model
terms apply (setup). Location embeddings are learned
geographic priors: changing the year does not create a new observation.
from earth_embedding import PointBuffer, TemporalSpec, OutputSpec, get_embedding
result = get_embedding(
"remoteclip",
spatial=PointBuffer(lon=-122.42, lat=37.77, buffer_m=320),
temporal=TemporalSpec.range("2021-05-01", "2021-10-31"),
output=OutputSpec.pooled(),
device="cpu",
)
print(result.data.shape, result.meta)This route fetches imagery through Earth Engine and needs the model's weights and
runtime. Already have pixels? get_image_embedding(model, pixels, spatial=..., temporal=..., sensor=..., device=...) accepts CHW or TCHW arrays in the adapter's exact band order and
units (API, models).
curl -L -o aef_index.parquet https://storage.googleapis.com/alphaearth_foundations/satellite_embedding/v1/annual/aef_index.parquetfrom earth_embedding import BBox, find_aef_tiles, sample_aef
tiles = find_aef_tiles("aef_index.parquet", spatial=BBox(-122.43, 37.76, -122.41, 37.78), year=2021)
result = sample_aef([[-122.42, 37.77]], tiles=tiles)
print(result.data.shape, result.meta["source_for_point"]) # (1, 64)The sampler handles CRS transforms, byte-range COG reads, int8 dequantization and
no-data; missing coverage raises unless strict=False. Google's
GCS guide describes
provider-paid access (as of July 2026) and annual coverage for 2017–2025; see
data access for indexes and the required attribution.
Image encoders, location encoders and precomputed products side by side. Each panel has its own PCA colors and keeps its native spatial support, so equal colors do not mean equal features or classes; this is a qualitative gallery, not a ranking. Image and product panels reuse verified historical Wuhan outputs (dates differ and are labeled); location panels are fresh inference. Inputs and reproduction.
from earth_embedding import compare_embeddings, plot_embedding_comparison
comparison = compare_embeddings(
["prithvi", "dofa", "remoteclip", "satclip", "geoclip", "esri_gle"],
spatial=spatial, temporal=temporal, output=OutputSpec.grid(),
model_options={m: {"grid_step_m": 80} for m in ("satclip", "geoclip", "esri_gle")},
on_error="record", # keep successful panels; show each failure explicitly
)
plot_embedding_comparison(comparison, columns=3).savefig("comparison.png", dpi=180)models=None selects the whole catalog. examples/compare_models.py
sets annual-product years for you and saves the figure, feature arrays and a run report
(--models satclip geoclip esri_gle --device cpu needs no imagery or Earth Engine).
Location encoders see only longitude and latitude; their patterns are learned
geographic priors. Change the region and spacing with spatial and grid_step_m.
Three runnable examples on a CPU, with no Earth Engine login. They use a bundled,
SHA-256-verified complete 72 × 88 grid of official AlphaEarth (AEF) 2021 overview cells
at 1,280 m over the San Francisco Bay Area (about 92 × 113 km, 6,336 cells, 2.3 MB).
Install with python -m pip install -e ".[demo,aef]".
1 · AEF 2021 → PCA map (offline)
from earth_embedding.demo import load_demo, pca_colors, plot_map
data = load_demo("aef")
colors = pca_colors(data.features)
fig = plot_map(data.samples, colors, title="San Francisco Bay Area · AEF 2021 · PCA RGB")
fig.savefig("aef-pca.png", dpi=160)2 · Esri GLE → location map (~3.7 MB weights, first run only)
from earth_embedding import get_location_embeddings
from earth_embedding.demo import load_demo, pca_colors, plot_map
data = load_demo("bayarea")
points = data.samples[["center_lon", "center_lat"]].to_numpy()
gle = get_location_embeddings("esri_gle", points, device="cpu", batch_size=128)
fig = plot_map(data.samples, pca_colors(gle.data), title="San Francisco Bay Area · Esri GLE · PCA RGB")
fig.savefig("esri-gle-pca.png", dpi=160)RGB shows three descriptive principal components, not land-cover classes, and colors
are not comparable between the two maps. fetch_aef_demo() repeats the official GCS reads.
3 · Embeddings + labels → held-out classification
from earth_embedding.demo import classify_demo, plot_classification
result = classify_demo()
print({k: result["metrics"][k] for k in ("oa", "macro_f1", "balanced_accuracy")})
fig = plot_classification(result)
fig.savefig("bayarea-classification.png", dpi=160)| OA | Macro-F1 | Balanced accuracy | Scored / buffer / not scored |
|---|---|---|---|
| 93.64% | 91.64% | 92.63% | 5,806 / 528 / 2 bare |
Two spatial folds: a model fitted only on the west half predicts the east half, and vice versa, so every scored cell has a held-out prediction. A 7.68 km buffer is never fitted or scored. Labels are ESA WorldCover 2021 (built, vegetation, cropland, water); the estimator is StandardScaler + class-balanced logistic regression. This is a regional software demo, not a paper benchmark. Split, class counts, sources and limits.
| Notebook | What it shows |
|---|---|
| 01 · First embedding map | Load the checked AEF sample and draw a PCA map |
| 02 · Esri GLE locations | Batch, cache and re-run a location encoder offline |
| 03 · Regional classification | Two-fold spatial holdout, maps and metrics |
| 04 · Export and reuse | ID-bearing batch export and safe re-alignment |
| 05 · Compare models | Three-model CPU comparison and the full-catalog cell |
All notebooks are stored with real outputs (execution receipt).
Models are organized by the object a user actually receives: A image encoders (A1 RGB, A2 fixed band schema, A3 channel-adaptive, A4 multi-temporal), B location encoders and C precomputed products (C1 gridded, C2 sampled). Architecture, resolution and training signal are separate properties.
| Stage | Interface | What to check |
|---|---|---|
| Discover | earth-embedding models --json, describe MODEL |
Input requirements, outputs, optional dependencies |
| Inspect imagery | inspect_provider_patch(...) |
Coverage, bands, values, shape, acquisition window |
| Encode images | get_embedding(...), get_image_embedding(...) |
Provider or local input; correct preprocessing |
| Encode locations | get_location_embeddings(...) |
WGS84 [lon, lat], checkpoint, device |
| Read AEF data | find_aef_tiles(...), sample_aef(...) |
Year, coverage, CRS, no-data, source URL |
| Scale up | get_embeddings_batch(...), export_batch(...) |
One configuration, cache, metadata, failures |
| Evaluate | examples/evaluate_embeddings.py |
Spatial splits, leakage, matched support |
Persist .data together with .meta. Feature dimensions and spatial support differ
between models; a shared interface does not make vectors from different encoders
interchangeable.
| Model ID | Class | Adapter input | Upstream | Weights or product |
|---|---|---|---|---|
remoteclip |
A1 · image | Sentinel-2 RGB | code | 🤗 model |
satmae |
A1 · image | Sentinel-2 RGB | code | 🤗 model |
satmaepp |
A1 · image | Sentinel-2 RGB | code | 🤗 model |
scalemae |
A1 · image | Sentinel-2 RGB + ground resolution | code | 🤗 model |
wildsat |
A1 · image | Sentinel-2 RGB | code | official |
satmaepp_s2_10b |
A2 · image | Sentinel-2 10 bands | code | 🤗 model |
prithvi |
A2 · image | Sentinel-2 6 bands + time/location | code | 🤗 model |
terrafm |
A2 · image | Sentinel-2 12 bands or Sentinel-1 VV/VH | code | 🤗 model |
terramind |
A2 · image | Sentinel-2 12 bands | code | 🤗 model |
satvision |
A2 · image | 14 calibrated MODIS TOA channels | code | 🤗 model |
dofa |
A3 · image | Multispectral imagery + wavelengths | code | 🤗 model |
fomo |
A3 · image | Sentinel-2 12 bands | code | official |
thor |
A3 · image | Sentinel-2 10 bands | code | 🤗 model |
galileo |
A4 · image | Sentinel-2 10-band time series | code | 🤗 model |
anysat |
A4 · image | Sentinel-2 10-band time series | code | 🤗 model |
agrifm |
A4 · image | Sentinel-2 10-band time series | code | official |
satclip |
B · location | Longitude/latitude, 256-D | code | 🤗 model |
geoclip |
B · location | Longitude/latitude, 512-D | code | official |
esri_gle |
B · location | Longitude/latitude, 256-D | docs | official |
gse |
C1 · product | Annual Google Satellite Embedding, 10 m, 64-D | catalog | official |
tessera |
C1 · product | Published GeoTessera tiles, 10 m | code | official |
copernicus |
C1 · product | 0.25° embedding grid | source | 🤗 dataset |
These are upstream resources, not weights republished by this project (packaging, default variants and terms). An adapter is an integration, not a guarantee of data access or of execution on your machine; see the validation report. The taxonomy also defines C2 sampled collections; no C2 adapter is claimed yet.
Our manuscript motivates the release taxonomy, comparable input/output contracts and evaluation provenance. Its frozen benchmark has 20 systems (A16 + B1 SatCLIP + C3); GeoCLIP and Esri GLE are later software integrations and do not expand that study. The manuscript is in preparation, and this repository claims no accepted paper, final leaderboard or scientific ranking (research scope).
Providers may require authentication, quotas or terms; some models need large checkpoints. A location encoder has no temporal observations, and resampling a coarse product does not make it a 10 m field. Read the limitations before designing a comparison.
Adapters with explicit input contracts, reproducible failure reports, small executable examples, provider-access fixes and English, Chinese or Japanese documentation are all welcome. Start with CONTRIBUTING.md, or open an issue with the model's official source, license, checkpoint and a concrete use case. The banner, logo and diagrams are editable Excalidraw sources (artwork guide).
Earth Embedding is an independently maintained extension of CyberGIS rs-embed, created by Dingqi Ye and contributors. We retain its Apache-2.0 license and acknowledge its APIs, adapters and engineering foundation. The upstream paper describes rs-embed; our manuscript and extensions are separate work (provenance).
We thank the rs-embed contributors, the model and dataset authors, Google Earth Engine, Google and Google DeepMind, TorchGeo, GeoTessera, TerraTorch, rshf, Microsoft SatCLIP, GeoCLIP, Esri and the wider Earth observation community. Integration does not imply endorsement.
Cite this software with the commit or release you used (CITATION.cff), the original rs-embed paper when you use its framework, and the publications of the models and data in your analysis.
@article{ye2026modelplacetimeremote,
title={Any Model, Any Place, Any Time: Get Remote Sensing Foundation Model Embeddings On Demand},
author={Ye, Dingqi and Kiv, Daniel and Hu, Wei and Shi, Jimeng and Wang, Shaowen},
year={2026},
eprint={2602.23678},
archivePrefix={arXiv},
url={https://arxiv.org/abs/2602.23678}
}Library code is Apache-2.0, with inherited attribution in NOTICE. Vendored components, model weights, data and fonts keep their own licenses: AlphaEarth data is CC-BY-4.0, ESA WorldCover is CC-BY-4.0, and Esri's software and model terms apply separately. See provenance and licensing.




