Feature Extraction
Transformers
Safetensors
English
remote-sensing
earth-observation
self-supervised-learning
satellite
multispectral
convnext
mae
mmearth
mp-mae
Instructions to use BiliSakura/MMEarth-transformers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use BiliSakura/MMEarth-transformers with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="BiliSakura/MMEarth-transformers")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("BiliSakura/MMEarth-transformers", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Upload MMEarth transformers checkpoints with model card metadata
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- README.md +164 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/config.json +70 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/model.safetensors +3 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/config.json +70 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/model.safetensors +3 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/config.json +70 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/model.safetensors +3 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/config.json +70 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/model.safetensors +3 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/config.json +70 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/model.safetensors +3 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/config.json +70 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/model.safetensors +3 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/config.json +61 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/model.safetensors +3 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/config.json +61 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/image_processing_mmearth.py +189 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/model.safetensors +3 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/modeling_mmearth.py +292 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/pipeline_mmearth.py +68 -0
- mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/preprocessor_config.json +18 -0
- mmearth-convnextv2-atto-s2-1m-64-uncertainty-56x8/config.json +70 -0
README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
tags:
|
| 6 |
+
- remote-sensing
|
| 7 |
+
- earth-observation
|
| 8 |
+
- self-supervised-learning
|
| 9 |
+
- satellite
|
| 10 |
+
- multispectral
|
| 11 |
+
- feature-extraction
|
| 12 |
+
- convnext
|
| 13 |
+
- mae
|
| 14 |
+
- mmearth
|
| 15 |
+
- mp-mae
|
| 16 |
+
- transformers
|
| 17 |
+
library_name: transformers
|
| 18 |
+
pipeline_tag: feature-extraction
|
| 19 |
+
---
|
| 20 |
+
|
| 21 |
+
# MMEarth Transformers Models
|
| 22 |
+
|
| 23 |
+
Hugging Face–compatible checkpoints converted from the official [MMEarth](https://arxiv.org/abs/2405.02771) MP-MAE pretrained weights. Each subfolder is a standalone model repo layout (`config.json`, `model.safetensors`, preprocessor, and remote code) for geospatial feature extraction.
|
| 24 |
+
|
| 25 |
+
## Model Description
|
| 26 |
+
|
| 27 |
+
These models are ConvNeXt V2 encoders pretrained with Multi Pretext Masked Autoencoding (MP-MAE) on the [MMEarth](https://github.com/vishalned/MMEarth-data) multi-modal geospatial dataset. Checkpoints cover different pretext task configurations (all modalities, S2-only, RGB/BGR, image-level, pixel-level) and model sizes (atto, tiny).
|
| 28 |
+
|
| 29 |
+
All folders ship self-contained remote code (`modeling_mmearth.py`, processor, pipeline) and load with `trust_remote_code=True`.
|
| 30 |
+
|
| 31 |
+
**Developed by:** [MMEarth Authors](https://github.com/vishalned/MMEarth-train)
|
| 32 |
+
**Converted for Hugging Face by:** BiliSakura
|
| 33 |
+
**License (weights):** MIT
|
| 34 |
+
**Original paper:** [MMEarth: Exploring Multi-Modal Pretext Tasks For Geospatial Representation Learning](https://arxiv.org/abs/2405.02771) (ECCV 2024)
|
| 35 |
+
|
| 36 |
+
## Available checkpoints (10 models)
|
| 37 |
+
|
| 38 |
+
| Folder | Input | Size | Dataset | Loss | Image | Patch | Ch |
|
| 39 |
+
|--------|-------|------|---------|------|-------|-------|----|
|
| 40 |
+
| `mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8` | all_mod | atto | 1M_64 | uncertainty | 56 | 8 | 12 |
|
| 41 |
+
| `mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8` | all_mod | atto | 1M_64 | unweighted | 56 | 8 | 12 |
|
| 42 |
+
| `mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16` | all_mod | atto | 1M_128 | uncertainty | 112 | 16 | 12 |
|
| 43 |
+
| `mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16` | all_mod | atto | 100k_128 | uncertainty | 112 | 16 | 12 |
|
| 44 |
+
| `mmearth-convnextv2-tiny-all-mod-1m-64-uncertainty-56x8` | all_mod | tiny | 1M_64 | uncertainty | 56 | 8 | 12 |
|
| 45 |
+
| `mmearth-convnextv2-atto-s2-1m-64-uncertainty-56x8` | S2 | atto | 1M_64 | uncertainty | 56 | 8 | 12 |
|
| 46 |
+
| `mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8` | rgb (BGR) | atto | 1M_64 | uncertainty | 56 | 8 | 3 |
|
| 47 |
+
| `mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16` | rgb (BGR) | atto | 1M_128 | uncertainty | 112 | 16 | 3 |
|
| 48 |
+
| `mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8` | img_mod | atto | 1M_64 | uncertainty | 56 | 8 | 12 |
|
| 49 |
+
| `mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8` | pix_mod | atto | 1M_64 | uncertainty | 56 | 8 | 12 |
|
| 50 |
+
|
| 51 |
+
Legacy `.pth` filename mapping is in [`conversion_manifest.json`](conversion_manifest.json).
|
| 52 |
+
|
| 53 |
+
## Usage
|
| 54 |
+
|
| 55 |
+
Processors default to **`do_resize: false`**. Inputs keep native height and width. Apply per-band MMEarth normalization when you have dataset statistics (`image_mean` / `image_std`).
|
| 56 |
+
|
| 57 |
+
```python
|
| 58 |
+
from transformers import pipeline
|
| 59 |
+
import numpy as np
|
| 60 |
+
|
| 61 |
+
MODEL = "/path/to/MMEarth-transformers/mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8"
|
| 62 |
+
|
| 63 |
+
pipe = pipeline(
|
| 64 |
+
task="mmearth-feature-extraction",
|
| 65 |
+
model=MODEL,
|
| 66 |
+
trust_remote_code=True,
|
| 67 |
+
)
|
| 68 |
+
|
| 69 |
+
# RGB/BGR: 3 bands at native size (56×56 for this checkpoint)
|
| 70 |
+
image = np.random.rand(56, 56, 3).astype(np.float32) * 1000
|
| 71 |
+
features = pipe(image, pool=True, return_tensors=True)
|
| 72 |
+
print(features.shape) # torch.Size([1, 320])
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
12-band Sentinel-2 (all_mod / S2 checkpoints):
|
| 76 |
+
|
| 77 |
+
```python
|
| 78 |
+
MODEL = "/path/to/MMEarth-transformers/mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8"
|
| 79 |
+
pipe = pipeline(task="mmearth-feature-extraction", model=MODEL, trust_remote_code=True)
|
| 80 |
+
|
| 81 |
+
image = np.random.rand(56, 56, 12).astype(np.float32) * 1000
|
| 82 |
+
features = pipe(image, pool=True, return_tensors=True)
|
| 83 |
+
print(features.shape) # torch.Size([1, 320])
|
| 84 |
+
```
|
| 85 |
+
|
| 86 |
+
Dense spatial token map:
|
| 87 |
+
|
| 88 |
+
```python
|
| 89 |
+
tokens = pipe(image, pool=False, return_tensors=True)
|
| 90 |
+
print(tokens.shape) # [1, num_patches, hidden_size]
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
To resize to the pretraining reference size:
|
| 94 |
+
|
| 95 |
+
```python
|
| 96 |
+
features = pipe(image, pool=True, return_tensors=True, image_processor_kwargs={"do_resize": True})
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
Load components directly:
|
| 100 |
+
|
| 101 |
+
```python
|
| 102 |
+
from transformers import AutoModel, AutoImageProcessor
|
| 103 |
+
|
| 104 |
+
model = AutoModel.from_pretrained(MODEL, trust_remote_code=True)
|
| 105 |
+
processor = AutoImageProcessor.from_pretrained(MODEL, trust_remote_code=True)
|
| 106 |
+
```
|
| 107 |
+
|
| 108 |
+
## Custom pipeline
|
| 109 |
+
|
| 110 |
+
Each checkpoint registers a custom pipeline in `config.json`:
|
| 111 |
+
|
| 112 |
+
```json
|
| 113 |
+
"custom_pipelines": {
|
| 114 |
+
"mmearth-feature-extraction": {
|
| 115 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 116 |
+
"pt": ["AutoModel"]
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
This follows the [HuggingFace custom pipeline pattern](https://huggingface.co/docs/transformers/add_new_pipeline): remote code ships with the model folder, and `trust_remote_code=True` loads `MMEarthImageFeatureExtractionPipeline`, which extends the standard `ImageFeatureExtractionPipeline` with numpy array and file path support.
|
| 122 |
+
|
| 123 |
+
The built-in `image-feature-extraction` task also works:
|
| 124 |
+
|
| 125 |
+
```python
|
| 126 |
+
pipe = pipeline(task="image-feature-extraction", model=MODEL, trust_remote_code=True)
|
| 127 |
+
```
|
| 128 |
+
|
| 129 |
+
## Normalization
|
| 130 |
+
|
| 131 |
+
MMEarth pretraining normalizes each band with dataset-specific mean/std from `data_*_band_stats.json`. The converted preprocessor defaults to `do_normalize: false` because band statistics are not embedded in the legacy checkpoints. Provide your own `image_mean` / `image_std` when preprocessing:
|
| 132 |
+
|
| 133 |
+
```python
|
| 134 |
+
features = pipe(
|
| 135 |
+
image,
|
| 136 |
+
pool=True,
|
| 137 |
+
return_tensors=True,
|
| 138 |
+
image_processor_kwargs={
|
| 139 |
+
"do_normalize": True,
|
| 140 |
+
"image_mean": [...], # one value per channel
|
| 141 |
+
"image_std": [...],
|
| 142 |
+
},
|
| 143 |
+
)
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
RGB checkpoints were trained with **BGR** channel order (bands B4, B3, B2). The processor swaps RGB→BGR when `channel_order="bgr"`.
|
| 147 |
+
|
| 148 |
+
## Dependencies
|
| 149 |
+
|
| 150 |
+
- `transformers`, `torch`, `timm`, `safetensors`
|
| 151 |
+
- `opencv-python` (multispectral resize with more than 4 channels when `do_resize=True`)
|
| 152 |
+
|
| 153 |
+
## Citation
|
| 154 |
+
|
| 155 |
+
```bibtex
|
| 156 |
+
@inproceedings{nedungadi2024mmearth,
|
| 157 |
+
title={MMEarth: Exploring multi-modal pretext tasks for geospatial representation learning},
|
| 158 |
+
author={Nedungadi, Vishal and Kariryaa, Ankit and Oehmcke, Stefan and Belongie, Serge and Igel, Christian and Lang, Nico},
|
| 159 |
+
booktitle={European Conference on Computer Vision},
|
| 160 |
+
pages={164--182},
|
| 161 |
+
year={2024},
|
| 162 |
+
organization={Springer}
|
| 163 |
+
}
|
| 164 |
+
```
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "100k_128",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 112,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "all_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 16,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-all_mod_atto_100k_128_uncertainty_112-16"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:73ad3615ab31506d9e2829912385adcb82140d3ab9c07784d37db8af5f2caaae
|
| 3 |
+
size 13573176
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-all-mod-100k-128-uncertainty-112x16/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 112,
|
| 5 |
+
"width": 112
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_128",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 112,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "all_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 16,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-all_mod_atto_1M_128_uncertainty_112-16"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f2f0e7cecf8534809972730b4960c07078387fc72f97e3d255ce20286803815b
|
| 3 |
+
size 13573176
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-all-mod-1m-128-uncertainty-112x16/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 112,
|
| 5 |
+
"width": 112
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_64",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 56,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "all_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 8,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-all_mod_atto_1M_64_uncertainty_56-8"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:cf0cfcaad31d7cd1cf4f7e730bec625d0f4d769eec25bf9aa3bed1e0bb105648
|
| 3 |
+
size 13572696
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-all-mod-1m-64-uncertainty-56x8/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 56,
|
| 5 |
+
"width": 56
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_64",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 56,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "all_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "unweighted",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 8,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-all_mod_atto_1M_64_unweighted_56-8"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:232078eaefd5615e3d4e8b9d7b3c0aa5836611b1bea18c3bfaa2f8b3aa397560
|
| 3 |
+
size 13572696
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-all-mod-1m-64-unweighted-56x8/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 56,
|
| 5 |
+
"width": 56
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_64",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 56,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "img_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 8,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-img_mod_atto_1M_64_uncertainty_56-8"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:1ec8508296b7288978f784efa4db9e9df14c52e9e74bb0d618c6eb4d28f45c98
|
| 3 |
+
size 13572696
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-img-mod-1m-64-uncertainty-56x8/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 56,
|
| 5 |
+
"width": 56
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_64",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 56,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "pix_mod",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 8,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-pix_mod_atto_1M_64_uncertainty_56-8"
|
| 70 |
+
}
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:527f40016c44e6183103af0ee0e0668cab617ccafe29868e1ea78570871f0905
|
| 3 |
+
size 13572696
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-pix-mod-1m-64-uncertainty-56x8/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 56,
|
| 5 |
+
"width": 56
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "rgb",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/config.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B4",
|
| 7 |
+
"B3",
|
| 8 |
+
"B2"
|
| 9 |
+
],
|
| 10 |
+
"channel_order": "bgr",
|
| 11 |
+
"checkpoint_stage": "pretrain",
|
| 12 |
+
"dataset": "1M_128",
|
| 13 |
+
"depths": [
|
| 14 |
+
2,
|
| 15 |
+
2,
|
| 16 |
+
6,
|
| 17 |
+
2
|
| 18 |
+
],
|
| 19 |
+
"do_rescale": false,
|
| 20 |
+
"drop_path_rate": 0.0,
|
| 21 |
+
"dtype": "float32",
|
| 22 |
+
"hidden_act": "gelu",
|
| 23 |
+
"hidden_size": 320,
|
| 24 |
+
"hidden_sizes": [
|
| 25 |
+
40,
|
| 26 |
+
80,
|
| 27 |
+
160,
|
| 28 |
+
320
|
| 29 |
+
],
|
| 30 |
+
"id2label": {},
|
| 31 |
+
"image_mean": null,
|
| 32 |
+
"image_size": 112,
|
| 33 |
+
"image_std": null,
|
| 34 |
+
"input_modality": "rgb",
|
| 35 |
+
"label2id": {},
|
| 36 |
+
"layer_norm_eps": 1e-06,
|
| 37 |
+
"loss_aggr": "uncertainty",
|
| 38 |
+
"model_size": "atto",
|
| 39 |
+
"model_type": "mmearth",
|
| 40 |
+
"num_channels": 3,
|
| 41 |
+
"num_stages": 4,
|
| 42 |
+
"patch_size": 16,
|
| 43 |
+
"rescale_factor": 1.0,
|
| 44 |
+
"transformers_version": "5.0.0",
|
| 45 |
+
"use_orig_stem": false,
|
| 46 |
+
"auto_map": {
|
| 47 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 48 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 49 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 50 |
+
},
|
| 51 |
+
"custom_pipelines": {
|
| 52 |
+
"mmearth-feature-extraction": {
|
| 53 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 54 |
+
"pt": [
|
| 55 |
+
"AutoModel"
|
| 56 |
+
]
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 60 |
+
"legacy_source": "pt-rgb_atto_1M_128_uncertainty_112-16"
|
| 61 |
+
}
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:0eb3fccae67ad295325778b6cf730834438b2d24ee0f71226aa7d4da9c8351aa
|
| 3 |
+
size 13560216
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-rgb-1m-128-uncertainty-112x16/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 112,
|
| 5 |
+
"width": 112
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "bgr",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/config.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B4",
|
| 7 |
+
"B3",
|
| 8 |
+
"B2"
|
| 9 |
+
],
|
| 10 |
+
"channel_order": "bgr",
|
| 11 |
+
"checkpoint_stage": "pretrain",
|
| 12 |
+
"dataset": "1M_64",
|
| 13 |
+
"depths": [
|
| 14 |
+
2,
|
| 15 |
+
2,
|
| 16 |
+
6,
|
| 17 |
+
2
|
| 18 |
+
],
|
| 19 |
+
"do_rescale": false,
|
| 20 |
+
"drop_path_rate": 0.0,
|
| 21 |
+
"dtype": "float32",
|
| 22 |
+
"hidden_act": "gelu",
|
| 23 |
+
"hidden_size": 320,
|
| 24 |
+
"hidden_sizes": [
|
| 25 |
+
40,
|
| 26 |
+
80,
|
| 27 |
+
160,
|
| 28 |
+
320
|
| 29 |
+
],
|
| 30 |
+
"id2label": {},
|
| 31 |
+
"image_mean": null,
|
| 32 |
+
"image_size": 56,
|
| 33 |
+
"image_std": null,
|
| 34 |
+
"input_modality": "rgb",
|
| 35 |
+
"label2id": {},
|
| 36 |
+
"layer_norm_eps": 1e-06,
|
| 37 |
+
"loss_aggr": "uncertainty",
|
| 38 |
+
"model_size": "atto",
|
| 39 |
+
"model_type": "mmearth",
|
| 40 |
+
"num_channels": 3,
|
| 41 |
+
"num_stages": 4,
|
| 42 |
+
"patch_size": 8,
|
| 43 |
+
"rescale_factor": 1.0,
|
| 44 |
+
"transformers_version": "5.0.0",
|
| 45 |
+
"use_orig_stem": false,
|
| 46 |
+
"auto_map": {
|
| 47 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 48 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 49 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 50 |
+
},
|
| 51 |
+
"custom_pipelines": {
|
| 52 |
+
"mmearth-feature-extraction": {
|
| 53 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 54 |
+
"pt": [
|
| 55 |
+
"AutoModel"
|
| 56 |
+
]
|
| 57 |
+
}
|
| 58 |
+
},
|
| 59 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 60 |
+
"legacy_source": "pt-rgb_atto_1M_64_uncertainty_56-8"
|
| 61 |
+
}
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/image_processing_mmearth.py
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""Image processor for MMEarth models."""
|
| 6 |
+
|
| 7 |
+
from typing import Optional, Union
|
| 8 |
+
|
| 9 |
+
import numpy as np
|
| 10 |
+
|
| 11 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 12 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 13 |
+
from transformers.image_utils import (
|
| 14 |
+
ChannelDimension,
|
| 15 |
+
ImageInput,
|
| 16 |
+
PILImageResampling,
|
| 17 |
+
infer_channel_dimension_format,
|
| 18 |
+
make_flat_list_of_images,
|
| 19 |
+
to_numpy_array,
|
| 20 |
+
valid_images,
|
| 21 |
+
validate_preprocess_arguments,
|
| 22 |
+
)
|
| 23 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
logger = logging.get_logger(__name__)
|
| 27 |
+
|
| 28 |
+
|
| 29 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 30 |
+
target_height, target_width = size["height"], size["width"]
|
| 31 |
+
|
| 32 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 33 |
+
image = np.transpose(image, (1, 2, 0))
|
| 34 |
+
|
| 35 |
+
height, width, _ = image.shape
|
| 36 |
+
if height == target_height and width == target_width:
|
| 37 |
+
resized = image
|
| 38 |
+
else:
|
| 39 |
+
try:
|
| 40 |
+
import cv2
|
| 41 |
+
except ImportError as exc:
|
| 42 |
+
raise ImportError(
|
| 43 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 44 |
+
) from exc
|
| 45 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 46 |
+
|
| 47 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 48 |
+
return np.transpose(resized, (2, 0, 1))
|
| 49 |
+
return resized
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def _reorder_channels(image: np.ndarray, channel_order: str, input_data_format: ChannelDimension) -> np.ndarray:
|
| 53 |
+
if channel_order != "bgr":
|
| 54 |
+
return image
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
if image.shape[0] < 3:
|
| 58 |
+
return image
|
| 59 |
+
return image[[2, 1, 0], ...]
|
| 60 |
+
if image.shape[-1] < 3:
|
| 61 |
+
return image
|
| 62 |
+
return image[..., [2, 1, 0]]
|
| 63 |
+
|
| 64 |
+
|
| 65 |
+
class MMEarthImageProcessor(BaseImageProcessor):
|
| 66 |
+
"""
|
| 67 |
+
Image processor for MMEarth ConvNeXt V2 encoders.
|
| 68 |
+
|
| 69 |
+
RGB checkpoints were trained with BGR channel order. Set `channel_order="bgr"` (default for RGB models) to swap
|
| 70 |
+
the first three channels from RGB to BGR before inference.
|
| 71 |
+
"""
|
| 72 |
+
|
| 73 |
+
model_input_names = ["pixel_values"]
|
| 74 |
+
|
| 75 |
+
def __init__(
|
| 76 |
+
self,
|
| 77 |
+
do_resize: bool = True,
|
| 78 |
+
size: Optional[dict[str, int]] = None,
|
| 79 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 80 |
+
do_rescale: bool = False,
|
| 81 |
+
rescale_factor: float = 1.0,
|
| 82 |
+
do_normalize: bool = True,
|
| 83 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 84 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 85 |
+
do_convert_rgb: bool = False,
|
| 86 |
+
channel_order: str = "rgb",
|
| 87 |
+
**kwargs,
|
| 88 |
+
):
|
| 89 |
+
super().__init__(**kwargs)
|
| 90 |
+
size = size if size is not None else {"height": 112, "width": 112}
|
| 91 |
+
self.do_resize = do_resize
|
| 92 |
+
self.size = size
|
| 93 |
+
self.resample = resample
|
| 94 |
+
self.do_rescale = do_rescale
|
| 95 |
+
self.rescale_factor = rescale_factor
|
| 96 |
+
self.do_normalize = do_normalize
|
| 97 |
+
self.image_mean = image_mean
|
| 98 |
+
self.image_std = image_std
|
| 99 |
+
self.do_convert_rgb = do_convert_rgb
|
| 100 |
+
self.channel_order = channel_order
|
| 101 |
+
|
| 102 |
+
@filter_out_non_signature_kwargs()
|
| 103 |
+
def preprocess(
|
| 104 |
+
self,
|
| 105 |
+
images: ImageInput,
|
| 106 |
+
do_resize: Optional[bool] = None,
|
| 107 |
+
size: Optional[dict[str, int]] = None,
|
| 108 |
+
resample: Optional[PILImageResampling] = None,
|
| 109 |
+
do_rescale: Optional[bool] = None,
|
| 110 |
+
rescale_factor: Optional[float] = None,
|
| 111 |
+
do_normalize: Optional[bool] = None,
|
| 112 |
+
image_mean: Optional[Union[float, list[float]]] = None,
|
| 113 |
+
image_std: Optional[Union[float, list[float]]] = None,
|
| 114 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 115 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 116 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 117 |
+
do_convert_rgb: Optional[bool] = None,
|
| 118 |
+
channel_order: Optional[str] = None,
|
| 119 |
+
):
|
| 120 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 121 |
+
size = size if size is not None else self.size
|
| 122 |
+
size = get_size_dict(size, default_to_square=True)
|
| 123 |
+
resample = resample if resample is not None else self.resample
|
| 124 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 125 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 126 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 127 |
+
image_mean = image_mean if image_mean is not None else self.image_mean
|
| 128 |
+
image_std = image_std if image_std is not None else self.image_std
|
| 129 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 130 |
+
channel_order = channel_order if channel_order is not None else self.channel_order
|
| 131 |
+
|
| 132 |
+
if do_normalize and (image_mean is None or image_std is None):
|
| 133 |
+
raise ValueError("Normalization requires `image_mean` and `image_std` with one value per channel.")
|
| 134 |
+
|
| 135 |
+
images = make_flat_list_of_images(images)
|
| 136 |
+
if not valid_images(images):
|
| 137 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 138 |
+
|
| 139 |
+
validate_preprocess_arguments(
|
| 140 |
+
do_rescale=do_rescale,
|
| 141 |
+
rescale_factor=rescale_factor,
|
| 142 |
+
do_normalize=do_normalize,
|
| 143 |
+
image_mean=image_mean,
|
| 144 |
+
image_std=image_std,
|
| 145 |
+
do_resize=do_resize,
|
| 146 |
+
size=size,
|
| 147 |
+
resample=resample,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
processed_images = []
|
| 151 |
+
for image in images:
|
| 152 |
+
image = to_numpy_array(image)
|
| 153 |
+
if do_convert_rgb:
|
| 154 |
+
image = self._convert_image_to_rgb(image)
|
| 155 |
+
|
| 156 |
+
if input_data_format is None:
|
| 157 |
+
try:
|
| 158 |
+
input_data_format = infer_channel_dimension_format(image)
|
| 159 |
+
except ValueError:
|
| 160 |
+
input_data_format = ChannelDimension.LAST
|
| 161 |
+
|
| 162 |
+
image = _reorder_channels(image, channel_order=channel_order, input_data_format=input_data_format)
|
| 163 |
+
|
| 164 |
+
if do_resize:
|
| 165 |
+
num_channels = image.shape[0] if input_data_format == ChannelDimension.FIRST else image.shape[-1]
|
| 166 |
+
if num_channels > 4:
|
| 167 |
+
image = _resize_multispectral(image, size=size, input_data_format=input_data_format)
|
| 168 |
+
else:
|
| 169 |
+
image = resize(
|
| 170 |
+
image,
|
| 171 |
+
size=(size["height"], size["width"]),
|
| 172 |
+
resample=resample,
|
| 173 |
+
input_data_format=input_data_format,
|
| 174 |
+
)
|
| 175 |
+
|
| 176 |
+
if do_rescale:
|
| 177 |
+
image = image * rescale_factor
|
| 178 |
+
|
| 179 |
+
if do_normalize:
|
| 180 |
+
image = self.normalize(image=image, mean=image_mean, std=image_std, input_data_format=input_data_format)
|
| 181 |
+
|
| 182 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=input_data_format)
|
| 183 |
+
processed_images.append(image)
|
| 184 |
+
|
| 185 |
+
data = {"pixel_values": processed_images}
|
| 186 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 187 |
+
|
| 188 |
+
|
| 189 |
+
__all__ = ["MMEarthImageProcessor"]
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:72548211ba30d3d39b82cd43c286a1c1ec94d46ae3ac7af873b16594bf0e052f
|
| 3 |
+
size 13559736
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/modeling_mmearth.py
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained MMEarth model and config for trust_remote_code loading."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
from typing import Optional
|
| 7 |
+
|
| 8 |
+
import torch
|
| 9 |
+
import torch.nn.functional as F
|
| 10 |
+
from timm.models.layers import DropPath, trunc_normal_
|
| 11 |
+
from torch import nn
|
| 12 |
+
|
| 13 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 14 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling, ImageClassifierOutput
|
| 15 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 16 |
+
from transformers.processing_utils import Unpack
|
| 17 |
+
from transformers.utils import TransformersKwargs, logging
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
logger = logging.get_logger(__name__)
|
| 21 |
+
|
| 22 |
+
MODEL_SIZE_PRESETS = {
|
| 23 |
+
"atto": {"depths": [2, 2, 6, 2], "hidden_sizes": [40, 80, 160, 320]},
|
| 24 |
+
"femto": {"depths": [2, 2, 6, 2], "hidden_sizes": [48, 96, 192, 384]},
|
| 25 |
+
"pico": {"depths": [2, 2, 6, 2], "hidden_sizes": [64, 128, 256, 512]},
|
| 26 |
+
"nano": {"depths": [2, 2, 8, 2], "hidden_sizes": [80, 160, 320, 640]},
|
| 27 |
+
"tiny": {"depths": [3, 3, 9, 3], "hidden_sizes": [96, 192, 384, 768]},
|
| 28 |
+
"base": {"depths": [3, 3, 27, 3], "hidden_sizes": [128, 256, 512, 1024]},
|
| 29 |
+
"large": {"depths": [3, 3, 27, 3], "hidden_sizes": [192, 384, 768, 1536]},
|
| 30 |
+
"huge": {"depths": [3, 3, 27, 3], "hidden_sizes": [352, 704, 1408, 2816]},
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class MMEarthConfig(PreTrainedConfig):
|
| 35 |
+
model_type = "mmearth"
|
| 36 |
+
|
| 37 |
+
def __init__(
|
| 38 |
+
self,
|
| 39 |
+
depths: list[int] | None = None,
|
| 40 |
+
hidden_sizes: list[int] | None = None,
|
| 41 |
+
num_channels: int = 12,
|
| 42 |
+
image_size: int = 112,
|
| 43 |
+
patch_size: int = 16,
|
| 44 |
+
drop_path_rate: float = 0.0,
|
| 45 |
+
layer_norm_eps: float = 1e-6,
|
| 46 |
+
hidden_act: str = "gelu",
|
| 47 |
+
use_orig_stem: bool = False,
|
| 48 |
+
model_size: str = "atto",
|
| 49 |
+
input_modality: str = "all_mod",
|
| 50 |
+
channel_order: str = "rgb",
|
| 51 |
+
dataset: str = "1M_128",
|
| 52 |
+
loss_aggr: str = "uncertainty",
|
| 53 |
+
checkpoint_stage: str = "pretrain",
|
| 54 |
+
image_mean: list[float] | None = None,
|
| 55 |
+
image_std: list[float] | None = None,
|
| 56 |
+
do_rescale: bool = False,
|
| 57 |
+
rescale_factor: float = 1.0,
|
| 58 |
+
num_labels: int = 0,
|
| 59 |
+
**kwargs,
|
| 60 |
+
):
|
| 61 |
+
super().__init__(**kwargs)
|
| 62 |
+
preset = MODEL_SIZE_PRESETS[model_size]
|
| 63 |
+
self.model_size = model_size
|
| 64 |
+
self.input_modality = input_modality
|
| 65 |
+
self.channel_order = channel_order
|
| 66 |
+
self.dataset = dataset
|
| 67 |
+
self.loss_aggr = loss_aggr
|
| 68 |
+
self.checkpoint_stage = checkpoint_stage
|
| 69 |
+
self.num_channels = num_channels
|
| 70 |
+
self.image_size = image_size
|
| 71 |
+
self.patch_size = patch_size
|
| 72 |
+
self.drop_path_rate = drop_path_rate
|
| 73 |
+
self.layer_norm_eps = layer_norm_eps
|
| 74 |
+
self.hidden_act = hidden_act
|
| 75 |
+
self.use_orig_stem = use_orig_stem
|
| 76 |
+
self.num_labels = num_labels
|
| 77 |
+
self.do_rescale = do_rescale
|
| 78 |
+
self.rescale_factor = rescale_factor
|
| 79 |
+
self.depths = depths if depths is not None else preset["depths"]
|
| 80 |
+
self.hidden_sizes = hidden_sizes if hidden_sizes is not None else preset["hidden_sizes"]
|
| 81 |
+
self.hidden_size = self.hidden_sizes[-1]
|
| 82 |
+
self.num_stages = len(self.depths)
|
| 83 |
+
self.image_mean = image_mean
|
| 84 |
+
self.image_std = image_std
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
class MMEarthLayerNorm(nn.Module):
|
| 88 |
+
def __init__(self, normalized_shape: int, eps: float = 1e-6, data_format: str = "channels_last"):
|
| 89 |
+
super().__init__()
|
| 90 |
+
self.weight = nn.Parameter(torch.ones(normalized_shape))
|
| 91 |
+
self.bias = nn.Parameter(torch.zeros(normalized_shape))
|
| 92 |
+
self.eps = eps
|
| 93 |
+
self.data_format = data_format
|
| 94 |
+
self.normalized_shape = (normalized_shape,)
|
| 95 |
+
|
| 96 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 97 |
+
if self.data_format == "channels_last":
|
| 98 |
+
return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
|
| 99 |
+
u = x.mean(1, keepdim=True)
|
| 100 |
+
s = (x - u).pow(2).mean(1, keepdim=True)
|
| 101 |
+
x = (x - u) / torch.sqrt(s + self.eps)
|
| 102 |
+
return self.weight[:, None, None] * x + self.bias[:, None, None]
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
class MMEarthGRN(nn.Module):
|
| 106 |
+
def __init__(self, dim: int):
|
| 107 |
+
super().__init__()
|
| 108 |
+
self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 109 |
+
self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))
|
| 110 |
+
|
| 111 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 112 |
+
gx = torch.norm(x, p=2, dim=(1, 2), keepdim=True)
|
| 113 |
+
nx = gx / (gx.mean(dim=-1, keepdim=True) + 1e-4)
|
| 114 |
+
return self.gamma * (x * nx) + self.beta + x
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
class MMEarthConvNeXtBlock(nn.Module):
|
| 118 |
+
def __init__(self, dim: int, drop_path: float = 0.0):
|
| 119 |
+
super().__init__()
|
| 120 |
+
self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim)
|
| 121 |
+
self.norm = MMEarthLayerNorm(dim, eps=1e-6)
|
| 122 |
+
self.pwconv1 = nn.Linear(dim, 4 * dim)
|
| 123 |
+
self.act = nn.GELU()
|
| 124 |
+
self.grn = MMEarthGRN(4 * dim)
|
| 125 |
+
self.pwconv2 = nn.Linear(4 * dim, dim)
|
| 126 |
+
self.drop_path = DropPath(drop_path) if drop_path > 0.0 else nn.Identity()
|
| 127 |
+
|
| 128 |
+
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
| 129 |
+
input_tensor = x
|
| 130 |
+
x = self.dwconv(x)
|
| 131 |
+
x = x.permute(0, 2, 3, 1)
|
| 132 |
+
x = self.norm(x)
|
| 133 |
+
x = self.pwconv1(x)
|
| 134 |
+
x = self.act(x)
|
| 135 |
+
x = self.grn(x)
|
| 136 |
+
x = self.pwconv2(x)
|
| 137 |
+
x = x.permute(0, 3, 1, 2)
|
| 138 |
+
return input_tensor + self.drop_path(x)
|
| 139 |
+
|
| 140 |
+
|
| 141 |
+
class MMEarthPreTrainedModel(PreTrainedModel):
|
| 142 |
+
config_class = MMEarthConfig
|
| 143 |
+
config: MMEarthConfig
|
| 144 |
+
base_model_prefix = "mmearth"
|
| 145 |
+
main_input_name = "pixel_values"
|
| 146 |
+
input_modalities = ("image",)
|
| 147 |
+
supports_gradient_checkpointing = True
|
| 148 |
+
_no_split_modules = ["MMEarthConvNeXtBlock"]
|
| 149 |
+
|
| 150 |
+
def _init_weights(self, module):
|
| 151 |
+
super()._init_weights(module)
|
| 152 |
+
if isinstance(module, (nn.Conv2d, nn.Linear)):
|
| 153 |
+
trunc_normal_(module.weight, std=0.02)
|
| 154 |
+
if module.bias is not None:
|
| 155 |
+
nn.init.constant_(module.bias, 0)
|
| 156 |
+
|
| 157 |
+
|
| 158 |
+
class MMEarthModel(MMEarthPreTrainedModel):
|
| 159 |
+
def __init__(self, config: MMEarthConfig, add_pooling_layer: bool = True):
|
| 160 |
+
super().__init__(config)
|
| 161 |
+
self.config = config
|
| 162 |
+
self.add_pooling_layer = add_pooling_layer
|
| 163 |
+
depths = config.depths
|
| 164 |
+
dims = config.hidden_sizes
|
| 165 |
+
patch_size = config.patch_size
|
| 166 |
+
num_stages = len(depths)
|
| 167 |
+
self.downsample_layers = nn.ModuleList()
|
| 168 |
+
if config.use_orig_stem:
|
| 169 |
+
self.stem_orig = nn.Sequential(
|
| 170 |
+
nn.Conv2d(
|
| 171 |
+
config.num_channels,
|
| 172 |
+
dims[0],
|
| 173 |
+
kernel_size=patch_size // (2 ** (num_stages - 1)),
|
| 174 |
+
stride=patch_size // (2 ** (num_stages - 1)),
|
| 175 |
+
),
|
| 176 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 177 |
+
)
|
| 178 |
+
self.initial_conv = None
|
| 179 |
+
self.stem = None
|
| 180 |
+
else:
|
| 181 |
+
self.stem_orig = None
|
| 182 |
+
self.initial_conv = nn.Sequential(
|
| 183 |
+
nn.Conv2d(config.num_channels, dims[0], kernel_size=3, stride=1),
|
| 184 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 185 |
+
nn.GELU(),
|
| 186 |
+
)
|
| 187 |
+
stem_kernel = patch_size // (2 ** (num_stages - 1))
|
| 188 |
+
self.stem = nn.Sequential(
|
| 189 |
+
nn.Conv2d(
|
| 190 |
+
dims[0],
|
| 191 |
+
dims[0],
|
| 192 |
+
kernel_size=stem_kernel,
|
| 193 |
+
stride=stem_kernel,
|
| 194 |
+
padding=stem_kernel // 2,
|
| 195 |
+
groups=dims[0],
|
| 196 |
+
),
|
| 197 |
+
MMEarthLayerNorm(dims[0], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 198 |
+
)
|
| 199 |
+
for i in range(3):
|
| 200 |
+
self.downsample_layers.append(
|
| 201 |
+
nn.Sequential(
|
| 202 |
+
MMEarthLayerNorm(dims[i], eps=config.layer_norm_eps, data_format="channels_first"),
|
| 203 |
+
nn.Conv2d(dims[i], dims[i + 1], kernel_size=2, stride=2),
|
| 204 |
+
)
|
| 205 |
+
)
|
| 206 |
+
dp_rates = [
|
| 207 |
+
x.item()
|
| 208 |
+
for x in torch.linspace(0, config.drop_path_rate, sum(depths), device=torch.device("cpu"))
|
| 209 |
+
]
|
| 210 |
+
cur = 0
|
| 211 |
+
self.stages = nn.ModuleList()
|
| 212 |
+
for i in range(num_stages):
|
| 213 |
+
stage = nn.Sequential(
|
| 214 |
+
*[MMEarthConvNeXtBlock(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
|
| 215 |
+
)
|
| 216 |
+
self.stages.append(stage)
|
| 217 |
+
cur += depths[i]
|
| 218 |
+
self.norm = nn.LayerNorm(dims[-1], eps=config.layer_norm_eps)
|
| 219 |
+
self.post_init()
|
| 220 |
+
|
| 221 |
+
def _forward_stem(self, x: torch.Tensor) -> torch.Tensor:
|
| 222 |
+
if self.config.use_orig_stem:
|
| 223 |
+
return self.stem_orig(x)
|
| 224 |
+
x = self.initial_conv(x)
|
| 225 |
+
return self.stem(x)
|
| 226 |
+
|
| 227 |
+
def forward_features(self, pixel_values: torch.Tensor) -> torch.Tensor:
|
| 228 |
+
x = self._forward_stem(pixel_values)
|
| 229 |
+
x = self.stages[0](x)
|
| 230 |
+
for i in range(3):
|
| 231 |
+
x = self.downsample_layers[i](x)
|
| 232 |
+
x = self.stages[i + 1](x)
|
| 233 |
+
return x
|
| 234 |
+
|
| 235 |
+
def forward(
|
| 236 |
+
self,
|
| 237 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 238 |
+
return_dict: Optional[bool] = None,
|
| 239 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 240 |
+
) -> BaseModelOutputWithPooling:
|
| 241 |
+
if pixel_values is None:
|
| 242 |
+
raise ValueError("You must specify `pixel_values`")
|
| 243 |
+
pixel_values = pixel_values.to(dtype=self.dtype)
|
| 244 |
+
if return_dict is None:
|
| 245 |
+
return_dict = self.config.use_return_dict
|
| 246 |
+
spatial_features = self.forward_features(pixel_values)
|
| 247 |
+
last_hidden_state = spatial_features.flatten(2).transpose(1, 2)
|
| 248 |
+
pooled_output = self.norm(spatial_features.mean([-2, -1])) if self.add_pooling_layer else None
|
| 249 |
+
if not return_dict:
|
| 250 |
+
return (last_hidden_state, pooled_output)
|
| 251 |
+
return BaseModelOutputWithPooling(last_hidden_state=last_hidden_state, pooler_output=pooled_output)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class MMEarthForImageClassification(MMEarthPreTrainedModel):
|
| 255 |
+
def __init__(self, config: MMEarthConfig):
|
| 256 |
+
super().__init__(config)
|
| 257 |
+
self.num_labels = config.num_labels
|
| 258 |
+
self.mmearth = MMEarthModel(config, add_pooling_layer=True)
|
| 259 |
+
self.classifier = (
|
| 260 |
+
nn.Linear(config.hidden_size, config.num_labels) if config.num_labels > 0 else nn.Identity()
|
| 261 |
+
)
|
| 262 |
+
self.post_init()
|
| 263 |
+
|
| 264 |
+
def forward(
|
| 265 |
+
self,
|
| 266 |
+
pixel_values: Optional[torch.Tensor] = None,
|
| 267 |
+
labels: Optional[torch.Tensor] = None,
|
| 268 |
+
return_dict: Optional[bool] = None,
|
| 269 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 270 |
+
) -> ImageClassifierOutput:
|
| 271 |
+
outputs = self.mmearth(pixel_values=pixel_values, return_dict=True, **kwargs)
|
| 272 |
+
logits = self.classifier(outputs.pooler_output)
|
| 273 |
+
loss = None
|
| 274 |
+
if labels is not None:
|
| 275 |
+
loss = self.loss_function(labels, logits, self.config, **kwargs)
|
| 276 |
+
if not return_dict:
|
| 277 |
+
output = (logits,) + outputs[1:]
|
| 278 |
+
return ((loss,) + output) if loss is not None else output
|
| 279 |
+
return ImageClassifierOutput(
|
| 280 |
+
loss=loss,
|
| 281 |
+
logits=logits,
|
| 282 |
+
hidden_states=outputs.hidden_states,
|
| 283 |
+
attentions=outputs.attentions,
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
|
| 287 |
+
__all__ = [
|
| 288 |
+
"MMEarthConfig",
|
| 289 |
+
"MMEarthForImageClassification",
|
| 290 |
+
"MMEarthModel",
|
| 291 |
+
"MMEarthPreTrainedModel",
|
| 292 |
+
]
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/pipeline_mmearth.py
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 MMEarth Authors and The HuggingFace Inc. team.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
"""MMEarth image feature extraction pipeline."""
|
| 6 |
+
|
| 7 |
+
from typing import Any, Union
|
| 8 |
+
|
| 9 |
+
from transformers.pipelines.base import GenericTensor, build_pipeline_init_args
|
| 10 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 11 |
+
from transformers.utils import add_end_docstrings, is_vision_available
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
if is_vision_available():
|
| 15 |
+
from transformers.image_utils import load_image
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
@add_end_docstrings(
|
| 19 |
+
build_pipeline_init_args(has_image_processor=True),
|
| 20 |
+
"""
|
| 21 |
+
pool (`bool`, *optional*, defaults to `False`):
|
| 22 |
+
Whether or not to return the pooled output. If `False`, the model will return the raw hidden states.
|
| 23 |
+
""",
|
| 24 |
+
)
|
| 25 |
+
class MMEarthImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 26 |
+
"""
|
| 27 |
+
MMEarth image feature extraction pipeline.
|
| 28 |
+
|
| 29 |
+
This pipeline wraps [`MMEarthModel`] for Sentinel-2 multispectral and RGB/BGR geospatial feature extraction.
|
| 30 |
+
It extends [`ImageFeatureExtractionPipeline`] with support for numpy arrays and file paths in addition to
|
| 31 |
+
standard image inputs.
|
| 32 |
+
"""
|
| 33 |
+
|
| 34 |
+
def _sanitize_parameters(
|
| 35 |
+
self,
|
| 36 |
+
image_processor_kwargs=None,
|
| 37 |
+
return_tensors=None,
|
| 38 |
+
pool=None,
|
| 39 |
+
**kwargs,
|
| 40 |
+
):
|
| 41 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 42 |
+
if "timeout" in kwargs:
|
| 43 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 44 |
+
|
| 45 |
+
postprocess_params = {}
|
| 46 |
+
if pool is not None:
|
| 47 |
+
postprocess_params["pool"] = pool
|
| 48 |
+
if return_tensors is not None:
|
| 49 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 50 |
+
|
| 51 |
+
return preprocess_params, {}, postprocess_params
|
| 52 |
+
|
| 53 |
+
def preprocess(self, image, timeout=None, **image_processor_kwargs) -> dict[str, GenericTensor]:
|
| 54 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 55 |
+
image = load_image(image, timeout=timeout)
|
| 56 |
+
model_inputs = self.image_processor(image, return_tensors="pt", **image_processor_kwargs)
|
| 57 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 58 |
+
return model_inputs
|
| 59 |
+
|
| 60 |
+
def __call__(
|
| 61 |
+
self,
|
| 62 |
+
*args: Union[str, Any, list[Any]],
|
| 63 |
+
**kwargs: Any,
|
| 64 |
+
) -> list[Any]:
|
| 65 |
+
return super().__call__(*args, **kwargs)
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
__all__ = ["MMEarthImageFeatureExtractionPipeline"]
|
mmearth-convnextv2-atto-rgb-1m-64-uncertainty-56x8/preprocessor_config.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "MMEarthImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 56,
|
| 5 |
+
"width": 56
|
| 6 |
+
},
|
| 7 |
+
"do_resize": false,
|
| 8 |
+
"do_rescale": false,
|
| 9 |
+
"rescale_factor": 1.0,
|
| 10 |
+
"do_normalize": false,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"channel_order": "bgr",
|
| 13 |
+
"image_mean": null,
|
| 14 |
+
"image_std": null,
|
| 15 |
+
"auto_map": {
|
| 16 |
+
"AutoImageProcessor": "image_processing_mmearth.MMEarthImageProcessor"
|
| 17 |
+
}
|
| 18 |
+
}
|
mmearth-convnextv2-atto-s2-1m-64-uncertainty-56x8/config.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"MMEarthModel"
|
| 4 |
+
],
|
| 5 |
+
"band_names": [
|
| 6 |
+
"B1",
|
| 7 |
+
"B2",
|
| 8 |
+
"B3",
|
| 9 |
+
"B4",
|
| 10 |
+
"B5",
|
| 11 |
+
"B6",
|
| 12 |
+
"B7",
|
| 13 |
+
"B8A",
|
| 14 |
+
"B8",
|
| 15 |
+
"B9",
|
| 16 |
+
"B11",
|
| 17 |
+
"B12"
|
| 18 |
+
],
|
| 19 |
+
"channel_order": "rgb",
|
| 20 |
+
"checkpoint_stage": "pretrain",
|
| 21 |
+
"dataset": "1M_64",
|
| 22 |
+
"depths": [
|
| 23 |
+
2,
|
| 24 |
+
2,
|
| 25 |
+
6,
|
| 26 |
+
2
|
| 27 |
+
],
|
| 28 |
+
"do_rescale": false,
|
| 29 |
+
"drop_path_rate": 0.0,
|
| 30 |
+
"dtype": "float32",
|
| 31 |
+
"hidden_act": "gelu",
|
| 32 |
+
"hidden_size": 320,
|
| 33 |
+
"hidden_sizes": [
|
| 34 |
+
40,
|
| 35 |
+
80,
|
| 36 |
+
160,
|
| 37 |
+
320
|
| 38 |
+
],
|
| 39 |
+
"id2label": {},
|
| 40 |
+
"image_mean": null,
|
| 41 |
+
"image_size": 56,
|
| 42 |
+
"image_std": null,
|
| 43 |
+
"input_modality": "S2",
|
| 44 |
+
"label2id": {},
|
| 45 |
+
"layer_norm_eps": 1e-06,
|
| 46 |
+
"loss_aggr": "uncertainty",
|
| 47 |
+
"model_size": "atto",
|
| 48 |
+
"model_type": "mmearth",
|
| 49 |
+
"num_channels": 12,
|
| 50 |
+
"num_stages": 4,
|
| 51 |
+
"patch_size": 8,
|
| 52 |
+
"rescale_factor": 1.0,
|
| 53 |
+
"transformers_version": "5.0.0",
|
| 54 |
+
"use_orig_stem": false,
|
| 55 |
+
"auto_map": {
|
| 56 |
+
"AutoConfig": "modeling_mmearth.MMEarthConfig",
|
| 57 |
+
"AutoModel": "modeling_mmearth.MMEarthModel",
|
| 58 |
+
"AutoModelForImageClassification": "modeling_mmearth.MMEarthForImageClassification"
|
| 59 |
+
},
|
| 60 |
+
"custom_pipelines": {
|
| 61 |
+
"mmearth-feature-extraction": {
|
| 62 |
+
"impl": "pipeline_mmearth.MMEarthImageFeatureExtractionPipeline",
|
| 63 |
+
"pt": [
|
| 64 |
+
"AutoModel"
|
| 65 |
+
]
|
| 66 |
+
}
|
| 67 |
+
},
|
| 68 |
+
"legacy_checkpoint": "checkpoint-199.pth",
|
| 69 |
+
"legacy_source": "pt-S2_atto_1M_64_uncertainty_56-8"
|
| 70 |
+
}
|