Feature Extraction
Transformers
Safetensors
English
remote-sensing
earth-observation
vision
croma
sentinel-1
sentinel-2
multimodal
Instructions to use BiliSakura/CROMA-transformers with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use BiliSakura/CROMA-transformers with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("feature-extraction", model="BiliSakura/CROMA-transformers")# Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("BiliSakura/CROMA-transformers", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Upload CROMA transformers checkpoints with model card metadata
Browse files- README.md +91 -0
- croma-base-patch8-120/config.json +32 -0
- croma-base-patch8-120/image_processing_croma.py +281 -0
- croma-base-patch8-120/model.safetensors +3 -0
- croma-base-patch8-120/modeling_croma.py +400 -0
- croma-base-patch8-120/pipeline_croma.py +115 -0
- croma-base-patch8-120/preprocessor_config.json +16 -0
- croma-large-patch8-120/config.json +32 -0
- croma-large-patch8-120/image_processing_croma.py +281 -0
- croma-large-patch8-120/model.safetensors +3 -0
- croma-large-patch8-120/modeling_croma.py +400 -0
- croma-large-patch8-120/pipeline_croma.py +115 -0
- croma-large-patch8-120/preprocessor_config.json +16 -0
README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: mit
|
| 3 |
+
language:
|
| 4 |
+
- en
|
| 5 |
+
tags:
|
| 6 |
+
- remote-sensing
|
| 7 |
+
- earth-observation
|
| 8 |
+
- vision
|
| 9 |
+
- feature-extraction
|
| 10 |
+
- croma
|
| 11 |
+
- sentinel-1
|
| 12 |
+
- sentinel-2
|
| 13 |
+
- multimodal
|
| 14 |
+
library_name: transformers
|
| 15 |
+
pipeline_tag: feature-extraction
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
# CROMA Transformers Models
|
| 19 |
+
|
| 20 |
+
Self-contained HuggingFace model checkpoints for [CROMA](https://arxiv.org/pdf/2311.00566.pdf). Each subfolder ships its own model, image processor, and custom pipeline code — no external `croma` package required.
|
| 21 |
+
|
| 22 |
+
CROMA expects dual-modality Sentinel-1 (2-channel SAR) and Sentinel-2 (12-channel optical) inputs at 120×120 px by default. Per-channel mean ± 2σ normalization is applied by the bundled image processor.
|
| 23 |
+
|
| 24 |
+
## Available checkpoints
|
| 25 |
+
|
| 26 |
+
| Folder | Hidden size | Optical layers | Heads |
|
| 27 |
+
|--------|-------------|----------------|-------|
|
| 28 |
+
| `croma-base-patch8-120/` | 768 | 12 | 16 |
|
| 29 |
+
| `croma-large-patch8-120/` | 1024 | 24 | 16 |
|
| 30 |
+
|
| 31 |
+
## Usage
|
| 32 |
+
|
| 33 |
+
```python
|
| 34 |
+
from transformers import pipeline
|
| 35 |
+
|
| 36 |
+
MODEL = "/path/to/CROMA-transformers/croma-base-patch8-120"
|
| 37 |
+
|
| 38 |
+
pipe = pipeline(
|
| 39 |
+
task="croma-feature-extraction",
|
| 40 |
+
model=MODEL,
|
| 41 |
+
trust_remote_code=True,
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
import numpy as np
|
| 45 |
+
|
| 46 |
+
sar = np.random.randn(2, 120, 120).astype(np.float32)
|
| 47 |
+
optical = np.random.randn(12, 120, 120).astype(np.float32)
|
| 48 |
+
|
| 49 |
+
joint_gap = pipe(
|
| 50 |
+
sar_images=sar,
|
| 51 |
+
optical_images=optical,
|
| 52 |
+
use_8_bit=True,
|
| 53 |
+
pool=True,
|
| 54 |
+
return_tensors=True,
|
| 55 |
+
)
|
| 56 |
+
|
| 57 |
+
sar_tokens = pipe(
|
| 58 |
+
sar_images=sar,
|
| 59 |
+
output_mode="sar",
|
| 60 |
+
pool=False,
|
| 61 |
+
return_tensors=True,
|
| 62 |
+
)
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
Or load components directly:
|
| 66 |
+
|
| 67 |
+
```python
|
| 68 |
+
from transformers import AutoModel, AutoImageProcessor
|
| 69 |
+
|
| 70 |
+
model = AutoModel.from_pretrained(MODEL, trust_remote_code=True)
|
| 71 |
+
processor = AutoImageProcessor.from_pretrained(MODEL, trust_remote_code=True)
|
| 72 |
+
|
| 73 |
+
batch = processor(sar_images=sar, optical_images=optical, return_tensors="pt")
|
| 74 |
+
outputs = model(**batch)
|
| 75 |
+
print(outputs.pooler_output.shape) # joint GAP
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
## Dependencies
|
| 79 |
+
|
| 80 |
+
- `transformers`
|
| 81 |
+
- `torch`
|
| 82 |
+
- `einops`
|
| 83 |
+
- `numpy`
|
| 84 |
+
- `opencv-python` (only when resizing non-RGB inputs)
|
| 85 |
+
|
| 86 |
+
## Rebuild from raw checkpoints
|
| 87 |
+
|
| 88 |
+
```bash
|
| 89 |
+
conda activate rsgen
|
| 90 |
+
python /path/to/projects/CROMA/scripts/build_transformers_repos.py
|
| 91 |
+
```
|
croma-base-patch8-120/config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"CromaModel"
|
| 4 |
+
],
|
| 5 |
+
"model_type": "croma",
|
| 6 |
+
"dtype": "float32",
|
| 7 |
+
"transformers_version": "5.0.0",
|
| 8 |
+
"hidden_size": 768,
|
| 9 |
+
"num_hidden_layers": 12,
|
| 10 |
+
"num_attention_heads": 16,
|
| 11 |
+
"patch_size": 8,
|
| 12 |
+
"image_size": 120,
|
| 13 |
+
"sar_channels": 2,
|
| 14 |
+
"optical_channels": 12,
|
| 15 |
+
"modality": "both",
|
| 16 |
+
"hidden_dropout_prob": 0.0,
|
| 17 |
+
"layer_norm_eps": 1e-05,
|
| 18 |
+
"initializer_range": 0.02,
|
| 19 |
+
"num_patches": 225,
|
| 20 |
+
"auto_map": {
|
| 21 |
+
"AutoConfig": "modeling_croma.CromaConfig",
|
| 22 |
+
"AutoModel": "modeling_croma.CromaModel"
|
| 23 |
+
},
|
| 24 |
+
"custom_pipelines": {
|
| 25 |
+
"croma-feature-extraction": {
|
| 26 |
+
"impl": "pipeline_croma.CROMAImageFeatureExtractionPipeline",
|
| 27 |
+
"pt": [
|
| 28 |
+
"AutoModel"
|
| 29 |
+
]
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
}
|
croma-base-patch8-120/image_processing_croma.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA 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 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Image processor for CROMA."""
|
| 15 |
+
|
| 16 |
+
from typing import Optional, Union
|
| 17 |
+
|
| 18 |
+
import numpy as np
|
| 19 |
+
|
| 20 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 21 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 22 |
+
from transformers.image_utils import (
|
| 23 |
+
ChannelDimension,
|
| 24 |
+
ImageInput,
|
| 25 |
+
PILImageResampling,
|
| 26 |
+
infer_channel_dimension_format,
|
| 27 |
+
make_flat_list_of_images,
|
| 28 |
+
to_numpy_array,
|
| 29 |
+
valid_images,
|
| 30 |
+
validate_preprocess_arguments,
|
| 31 |
+
)
|
| 32 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
logger = logging.get_logger(__name__)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 39 |
+
target_height, target_width = size["height"], size["width"]
|
| 40 |
+
|
| 41 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 42 |
+
image = np.transpose(image, (1, 2, 0))
|
| 43 |
+
|
| 44 |
+
height, width, _ = image.shape
|
| 45 |
+
if height == target_height and width == target_width:
|
| 46 |
+
resized = image
|
| 47 |
+
else:
|
| 48 |
+
try:
|
| 49 |
+
import cv2
|
| 50 |
+
except ImportError as exc:
|
| 51 |
+
raise ImportError(
|
| 52 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 53 |
+
) from exc
|
| 54 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
return np.transpose(resized, (2, 0, 1))
|
| 58 |
+
return resized
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def normalize_croma_channels(
|
| 62 |
+
images: np.ndarray,
|
| 63 |
+
input_data_format: ChannelDimension,
|
| 64 |
+
use_8_bit: bool = False,
|
| 65 |
+
) -> np.ndarray:
|
| 66 |
+
"""
|
| 67 |
+
Apply per-channel mean +/- 2*std normalization used by CROMA (SatMAE / SeCo style).
|
| 68 |
+
|
| 69 |
+
Args:
|
| 70 |
+
images (`np.ndarray`):
|
| 71 |
+
Input image array in channels-first or channels-last format.
|
| 72 |
+
input_data_format (`ChannelDimension`):
|
| 73 |
+
Whether channels are first or last.
|
| 74 |
+
use_8_bit (`bool`, *optional*, defaults to `False`):
|
| 75 |
+
If `True`, scale to `[0, 255]` and cast to `uint8`. Otherwise scale to `[0, 1]`.
|
| 76 |
+
"""
|
| 77 |
+
if input_data_format == ChannelDimension.LAST:
|
| 78 |
+
images = np.transpose(images, (2, 0, 1))
|
| 79 |
+
|
| 80 |
+
normalized_channels = []
|
| 81 |
+
for channel in range(images.shape[0]):
|
| 82 |
+
channel_data = images[channel].astype(np.float32)
|
| 83 |
+
min_value = channel_data.mean() - 2 * channel_data.std()
|
| 84 |
+
max_value = channel_data.mean() + 2 * channel_data.std()
|
| 85 |
+
denominator = max_value - min_value
|
| 86 |
+
if denominator == 0:
|
| 87 |
+
denominator = 1.0
|
| 88 |
+
|
| 89 |
+
if use_8_bit:
|
| 90 |
+
channel_data = (channel_data - min_value) / denominator * 255.0
|
| 91 |
+
channel_data = np.clip(channel_data, 0, 255).astype(np.uint8)
|
| 92 |
+
else:
|
| 93 |
+
channel_data = (channel_data - min_value) / denominator
|
| 94 |
+
channel_data = np.clip(channel_data, 0, 1).astype(np.float32)
|
| 95 |
+
|
| 96 |
+
normalized_channels.append(channel_data)
|
| 97 |
+
|
| 98 |
+
normalized = np.stack(normalized_channels, axis=0)
|
| 99 |
+
if input_data_format == ChannelDimension.LAST:
|
| 100 |
+
return np.transpose(normalized, (1, 2, 0))
|
| 101 |
+
return normalized
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class CromaImageProcessor(BaseImageProcessor):
|
| 105 |
+
"""
|
| 106 |
+
Image processor for CROMA models.
|
| 107 |
+
|
| 108 |
+
CROMA accepts separate Sentinel-1 SAR (2 channels) and Sentinel-2 optical (12 channels) inputs. The processor
|
| 109 |
+
applies per-channel mean +/- 2*std normalization and optional resizing.
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
model_input_names = ["sar_pixel_values", "optical_pixel_values"]
|
| 113 |
+
|
| 114 |
+
def __init__(
|
| 115 |
+
self,
|
| 116 |
+
do_resize: bool = True,
|
| 117 |
+
size: Optional[dict[str, int]] = None,
|
| 118 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 119 |
+
do_rescale: bool = True,
|
| 120 |
+
rescale_factor: float = 1 / 255.0,
|
| 121 |
+
do_normalize: bool = True,
|
| 122 |
+
use_8_bit: bool = False,
|
| 123 |
+
do_convert_rgb: bool = False,
|
| 124 |
+
**kwargs,
|
| 125 |
+
):
|
| 126 |
+
super().__init__(**kwargs)
|
| 127 |
+
size = size if size is not None else {"height": 120, "width": 120}
|
| 128 |
+
self.do_resize = do_resize
|
| 129 |
+
self.size = size
|
| 130 |
+
self.resample = resample
|
| 131 |
+
self.do_rescale = do_rescale
|
| 132 |
+
self.rescale_factor = rescale_factor
|
| 133 |
+
self.do_normalize = do_normalize
|
| 134 |
+
self.use_8_bit = use_8_bit
|
| 135 |
+
self.do_convert_rgb = do_convert_rgb
|
| 136 |
+
|
| 137 |
+
def _preprocess_modality(
|
| 138 |
+
self,
|
| 139 |
+
images: ImageInput,
|
| 140 |
+
expected_channels: Optional[int],
|
| 141 |
+
do_resize: bool,
|
| 142 |
+
size: dict[str, int],
|
| 143 |
+
resample: PILImageResampling,
|
| 144 |
+
do_rescale: bool,
|
| 145 |
+
rescale_factor: float,
|
| 146 |
+
do_normalize: bool,
|
| 147 |
+
use_8_bit: bool,
|
| 148 |
+
do_convert_rgb: bool,
|
| 149 |
+
data_format: Union[str, ChannelDimension],
|
| 150 |
+
input_data_format: Optional[Union[str, ChannelDimension]],
|
| 151 |
+
) -> list[np.ndarray]:
|
| 152 |
+
images = make_flat_list_of_images(images)
|
| 153 |
+
if not valid_images(images):
|
| 154 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 155 |
+
|
| 156 |
+
processed_images = []
|
| 157 |
+
for image in images:
|
| 158 |
+
image = to_numpy_array(image)
|
| 159 |
+
if do_convert_rgb:
|
| 160 |
+
image = self._convert_image_to_rgb(image)
|
| 161 |
+
|
| 162 |
+
if input_data_format is None:
|
| 163 |
+
if isinstance(image, np.ndarray) and image.ndim == 3:
|
| 164 |
+
# CROMA expects channels-first tensors; prefer FIRST when the leading axis looks like channels.
|
| 165 |
+
current_input_format = (
|
| 166 |
+
ChannelDimension.FIRST if image.shape[0] <= image.shape[-1] else ChannelDimension.LAST
|
| 167 |
+
)
|
| 168 |
+
else:
|
| 169 |
+
try:
|
| 170 |
+
current_input_format = infer_channel_dimension_format(image)
|
| 171 |
+
except ValueError:
|
| 172 |
+
current_input_format = ChannelDimension.LAST
|
| 173 |
+
else:
|
| 174 |
+
current_input_format = input_data_format
|
| 175 |
+
|
| 176 |
+
num_channels = image.shape[-1] if current_input_format == ChannelDimension.LAST else image.shape[0]
|
| 177 |
+
if expected_channels is not None and num_channels != expected_channels:
|
| 178 |
+
raise ValueError(
|
| 179 |
+
f"Expected {expected_channels} channels for this modality, but got {num_channels}."
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
if do_normalize:
|
| 183 |
+
image = normalize_croma_channels(
|
| 184 |
+
image,
|
| 185 |
+
input_data_format=current_input_format,
|
| 186 |
+
use_8_bit=use_8_bit,
|
| 187 |
+
)
|
| 188 |
+
if use_8_bit and do_rescale:
|
| 189 |
+
image = image.astype(np.float32) / 255.0
|
| 190 |
+
elif do_rescale:
|
| 191 |
+
image = image * rescale_factor
|
| 192 |
+
|
| 193 |
+
if do_resize:
|
| 194 |
+
if num_channels != 3:
|
| 195 |
+
image = _resize_multispectral(image, size=size, input_data_format=current_input_format)
|
| 196 |
+
else:
|
| 197 |
+
image = resize(image, size=size, resample=resample, input_data_format=current_input_format)
|
| 198 |
+
|
| 199 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=current_input_format)
|
| 200 |
+
processed_images.append(image)
|
| 201 |
+
|
| 202 |
+
return processed_images
|
| 203 |
+
|
| 204 |
+
@filter_out_non_signature_kwargs()
|
| 205 |
+
def preprocess(
|
| 206 |
+
self,
|
| 207 |
+
images: Optional[ImageInput] = None,
|
| 208 |
+
sar_images: Optional[ImageInput] = None,
|
| 209 |
+
optical_images: Optional[ImageInput] = None,
|
| 210 |
+
do_resize: Optional[bool] = None,
|
| 211 |
+
size: Optional[dict[str, int]] = None,
|
| 212 |
+
resample: Optional[PILImageResampling] = None,
|
| 213 |
+
do_rescale: Optional[bool] = None,
|
| 214 |
+
rescale_factor: Optional[float] = None,
|
| 215 |
+
do_normalize: Optional[bool] = None,
|
| 216 |
+
use_8_bit: Optional[bool] = None,
|
| 217 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 218 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 219 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 220 |
+
do_convert_rgb: Optional[bool] = None,
|
| 221 |
+
):
|
| 222 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 223 |
+
size = size if size is not None else self.size
|
| 224 |
+
size = get_size_dict(size, default_to_square=True)
|
| 225 |
+
resample = resample if resample is not None else self.resample
|
| 226 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 227 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 228 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 229 |
+
use_8_bit = use_8_bit if use_8_bit is not None else self.use_8_bit
|
| 230 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 231 |
+
|
| 232 |
+
validate_preprocess_arguments(
|
| 233 |
+
do_rescale=do_rescale,
|
| 234 |
+
rescale_factor=rescale_factor,
|
| 235 |
+
do_normalize=False,
|
| 236 |
+
do_resize=do_resize,
|
| 237 |
+
size=size,
|
| 238 |
+
resample=resample,
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
if sar_images is None and optical_images is None:
|
| 242 |
+
if images is None:
|
| 243 |
+
raise ValueError("Provide `sar_images`, `optical_images`, or legacy `images` for preprocessing.")
|
| 244 |
+
optical_images = images
|
| 245 |
+
|
| 246 |
+
data = {}
|
| 247 |
+
if sar_images is not None:
|
| 248 |
+
data["sar_pixel_values"] = self._preprocess_modality(
|
| 249 |
+
sar_images,
|
| 250 |
+
expected_channels=2,
|
| 251 |
+
do_resize=do_resize,
|
| 252 |
+
size=size,
|
| 253 |
+
resample=resample,
|
| 254 |
+
do_rescale=do_rescale,
|
| 255 |
+
rescale_factor=rescale_factor,
|
| 256 |
+
do_normalize=do_normalize,
|
| 257 |
+
use_8_bit=use_8_bit,
|
| 258 |
+
do_convert_rgb=do_convert_rgb,
|
| 259 |
+
data_format=data_format,
|
| 260 |
+
input_data_format=input_data_format,
|
| 261 |
+
)
|
| 262 |
+
if optical_images is not None:
|
| 263 |
+
data["optical_pixel_values"] = self._preprocess_modality(
|
| 264 |
+
optical_images,
|
| 265 |
+
expected_channels=12,
|
| 266 |
+
do_resize=do_resize,
|
| 267 |
+
size=size,
|
| 268 |
+
resample=resample,
|
| 269 |
+
do_rescale=do_rescale,
|
| 270 |
+
rescale_factor=rescale_factor,
|
| 271 |
+
do_normalize=do_normalize,
|
| 272 |
+
use_8_bit=use_8_bit,
|
| 273 |
+
do_convert_rgb=do_convert_rgb,
|
| 274 |
+
data_format=data_format,
|
| 275 |
+
input_data_format=input_data_format,
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
__all__ = ["CromaImageProcessor", "normalize_croma_channels"]
|
croma-base-patch8-120/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:919724c6bca3b6eb08aa9be297230f5a142d57d1a0ca643b8596e665e991cca8
|
| 3 |
+
size 777500064
|
croma-base-patch8-120/modeling_croma.py
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained CROMA model and configuration."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import itertools
|
| 7 |
+
import math
|
| 8 |
+
from dataclasses import dataclass
|
| 9 |
+
from typing import Optional
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from einops import rearrange
|
| 13 |
+
from torch import einsum, nn
|
| 14 |
+
|
| 15 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 16 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling
|
| 17 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 18 |
+
from transformers.processing_utils import Unpack
|
| 19 |
+
from transformers.utils import TransformersKwargs, logging
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
logger = logging.get_logger(__name__)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class CromaConfig(PreTrainedConfig):
|
| 26 |
+
model_type = "croma"
|
| 27 |
+
|
| 28 |
+
def __init__(
|
| 29 |
+
self,
|
| 30 |
+
hidden_size=768,
|
| 31 |
+
num_hidden_layers=12,
|
| 32 |
+
num_attention_heads=16,
|
| 33 |
+
patch_size=8,
|
| 34 |
+
image_size=120,
|
| 35 |
+
sar_channels=2,
|
| 36 |
+
optical_channels=12,
|
| 37 |
+
modality="both",
|
| 38 |
+
hidden_dropout_prob=0.0,
|
| 39 |
+
layer_norm_eps=1e-5,
|
| 40 |
+
initializer_range=0.02,
|
| 41 |
+
num_patches=None,
|
| 42 |
+
**kwargs,
|
| 43 |
+
):
|
| 44 |
+
super().__init__(**kwargs)
|
| 45 |
+
|
| 46 |
+
if image_size % patch_size != 0:
|
| 47 |
+
raise ValueError(f"`image_size` ({image_size}) must be divisible by `patch_size` ({patch_size}).")
|
| 48 |
+
|
| 49 |
+
if modality not in {"both", "sar", "optical"}:
|
| 50 |
+
raise ValueError(f"`modality` must be one of 'both', 'sar', or 'optical', got {modality!r}.")
|
| 51 |
+
|
| 52 |
+
self.hidden_size = hidden_size
|
| 53 |
+
self.num_hidden_layers = num_hidden_layers
|
| 54 |
+
self.num_attention_heads = num_attention_heads
|
| 55 |
+
self.patch_size = patch_size
|
| 56 |
+
self.image_size = image_size
|
| 57 |
+
self.sar_channels = sar_channels
|
| 58 |
+
self.optical_channels = optical_channels
|
| 59 |
+
self.modality = modality
|
| 60 |
+
self.hidden_dropout_prob = hidden_dropout_prob
|
| 61 |
+
self.layer_norm_eps = layer_norm_eps
|
| 62 |
+
self.initializer_range = initializer_range
|
| 63 |
+
self.num_patches = num_patches if num_patches is not None else (image_size // patch_size) ** 2
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_2dalibi(num_heads: int, num_patches: int) -> torch.Tensor:
|
| 67 |
+
grid_size = int(math.sqrt(num_patches))
|
| 68 |
+
points = list(itertools.product(range(grid_size), range(grid_size)))
|
| 69 |
+
|
| 70 |
+
def get_slopes(n):
|
| 71 |
+
def get_slopes_power_of_2(n):
|
| 72 |
+
start = 2 ** (-2 ** -(math.log2(n) - 3))
|
| 73 |
+
ratio = start
|
| 74 |
+
return [start * ratio**i for i in range(n)]
|
| 75 |
+
|
| 76 |
+
if math.log2(n).is_integer():
|
| 77 |
+
return get_slopes_power_of_2(n)
|
| 78 |
+
closest_power_of_2 = 2 ** math.floor(math.log2(n))
|
| 79 |
+
return get_slopes_power_of_2(closest_power_of_2) + get_slopes(2 * closest_power_of_2)[0::2][
|
| 80 |
+
: n - closest_power_of_2
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
slopes = torch.tensor(get_slopes(num_heads), dtype=torch.float32).unsqueeze(1)
|
| 84 |
+
idxs = []
|
| 85 |
+
for p1 in points:
|
| 86 |
+
for p2 in points:
|
| 87 |
+
dist = math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
| 88 |
+
idxs.append(dist * slopes * -1)
|
| 89 |
+
all_bias = torch.cat(idxs, dim=1)
|
| 90 |
+
return all_bias.view(1, num_heads, num_patches, num_patches)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
@dataclass
|
| 94 |
+
class CromaModelOutput(BaseModelOutputWithPooling):
|
| 95 |
+
sar_hidden_states: Optional[torch.FloatTensor] = None
|
| 96 |
+
sar_pooler_output: Optional[torch.FloatTensor] = None
|
| 97 |
+
optical_hidden_states: Optional[torch.FloatTensor] = None
|
| 98 |
+
optical_pooler_output: Optional[torch.FloatTensor] = None
|
| 99 |
+
joint_hidden_states: Optional[torch.FloatTensor] = None
|
| 100 |
+
joint_pooler_output: Optional[torch.FloatTensor] = None
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class CromaFeedForward(nn.Module):
|
| 104 |
+
def __init__(self, config: CromaConfig, mult: int = 4):
|
| 105 |
+
super().__init__()
|
| 106 |
+
inner_dim = int(config.hidden_size * mult)
|
| 107 |
+
self.net = nn.Sequential(
|
| 108 |
+
nn.Linear(config.hidden_size, inner_dim),
|
| 109 |
+
nn.GELU(),
|
| 110 |
+
nn.Dropout(config.hidden_dropout_prob),
|
| 111 |
+
nn.Linear(inner_dim, config.hidden_size),
|
| 112 |
+
)
|
| 113 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 114 |
+
|
| 115 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 116 |
+
hidden_states = self.input_norm(hidden_states)
|
| 117 |
+
return self.net(hidden_states)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
class CromaAttention(nn.Module):
|
| 121 |
+
def __init__(self, config: CromaConfig):
|
| 122 |
+
super().__init__()
|
| 123 |
+
self.num_attention_heads = config.num_attention_heads
|
| 124 |
+
self.attention_head_size = config.hidden_size // config.num_attention_heads
|
| 125 |
+
self.scale = self.attention_head_size**-0.5
|
| 126 |
+
|
| 127 |
+
self.to_qkv = nn.Linear(config.hidden_size, config.hidden_size * 3, bias=False)
|
| 128 |
+
self.to_out = nn.Linear(config.hidden_size, config.hidden_size)
|
| 129 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 130 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 131 |
+
|
| 132 |
+
def forward(self, hidden_states: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 133 |
+
hidden_states = self.input_norm(hidden_states)
|
| 134 |
+
query, key, value = self.to_qkv(hidden_states).chunk(3, dim=-1)
|
| 135 |
+
query, key, value = map(
|
| 136 |
+
lambda tensor: rearrange(tensor, "b n (h d) -> b h n d", h=self.num_attention_heads),
|
| 137 |
+
(query, key, value),
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
attention_scores = einsum("b h i d, b h j d -> b h i j", query, key) * self.scale
|
| 141 |
+
attention_scores = attention_scores + relative_position_bias
|
| 142 |
+
attention_probs = attention_scores.softmax(dim=-1)
|
| 143 |
+
attention_probs = self.dropout(attention_probs)
|
| 144 |
+
|
| 145 |
+
context = einsum("b h i j, b h j d -> b h i d", attention_probs, value)
|
| 146 |
+
context = rearrange(context, "b h n d -> b n (h d)")
|
| 147 |
+
return self.to_out(context)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class CromaCrossAttention(nn.Module):
|
| 151 |
+
def __init__(self, config: CromaConfig):
|
| 152 |
+
super().__init__()
|
| 153 |
+
self.num_attention_heads = config.num_attention_heads
|
| 154 |
+
self.attention_head_size = config.hidden_size // config.num_attention_heads
|
| 155 |
+
self.scale = self.attention_head_size**-0.5
|
| 156 |
+
|
| 157 |
+
self.to_q = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 158 |
+
self.to_k = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 159 |
+
self.to_v = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 160 |
+
self.to_out = nn.Linear(config.hidden_size, config.hidden_size)
|
| 161 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 162 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 163 |
+
|
| 164 |
+
def forward(
|
| 165 |
+
self,
|
| 166 |
+
hidden_states: torch.Tensor,
|
| 167 |
+
context: torch.Tensor,
|
| 168 |
+
relative_position_bias: torch.Tensor,
|
| 169 |
+
) -> torch.Tensor:
|
| 170 |
+
hidden_states = self.input_norm(hidden_states)
|
| 171 |
+
context = self.input_norm(context)
|
| 172 |
+
|
| 173 |
+
query = self.to_q(hidden_states)
|
| 174 |
+
key = self.to_k(context)
|
| 175 |
+
value = self.to_v(context)
|
| 176 |
+
query, key, value = map(
|
| 177 |
+
lambda tensor: rearrange(tensor, "b n (h d) -> b h n d", h=self.num_attention_heads),
|
| 178 |
+
(query, key, value),
|
| 179 |
+
)
|
| 180 |
+
|
| 181 |
+
attention_scores = einsum("b h i d, b h j d -> b h i j", query, key) * self.scale
|
| 182 |
+
attention_scores = attention_scores + relative_position_bias
|
| 183 |
+
attention_probs = attention_scores.softmax(dim=-1)
|
| 184 |
+
attention_probs = self.dropout(attention_probs)
|
| 185 |
+
|
| 186 |
+
context = einsum("b h i j, b h j d -> b h i d", attention_probs, value)
|
| 187 |
+
context = rearrange(context, "b h n d -> b n (h d)")
|
| 188 |
+
return self.to_out(context)
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class CromaEncoder(nn.Module):
|
| 192 |
+
def __init__(self, config: CromaConfig, depth: int, final_norm: bool = True):
|
| 193 |
+
super().__init__()
|
| 194 |
+
self.layers = nn.ModuleList(
|
| 195 |
+
[
|
| 196 |
+
nn.ModuleList([CromaAttention(config), CromaFeedForward(config)])
|
| 197 |
+
for _ in range(depth)
|
| 198 |
+
]
|
| 199 |
+
)
|
| 200 |
+
self.norm_out = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps) if final_norm else None
|
| 201 |
+
|
| 202 |
+
def forward(self, hidden_states: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 203 |
+
for self_attn, ffn in self.layers:
|
| 204 |
+
hidden_states = self_attn(hidden_states, relative_position_bias) + hidden_states
|
| 205 |
+
hidden_states = ffn(hidden_states) + hidden_states
|
| 206 |
+
if self.norm_out is not None:
|
| 207 |
+
return self.norm_out(hidden_states)
|
| 208 |
+
return hidden_states
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
class CromaCrossEncoder(nn.Module):
|
| 212 |
+
def __init__(self, config: CromaConfig, depth: int):
|
| 213 |
+
super().__init__()
|
| 214 |
+
self.layers = nn.ModuleList(
|
| 215 |
+
[
|
| 216 |
+
nn.ModuleList([CromaAttention(config), CromaCrossAttention(config), CromaFeedForward(config)])
|
| 217 |
+
for _ in range(depth)
|
| 218 |
+
]
|
| 219 |
+
)
|
| 220 |
+
self.norm_out = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 221 |
+
|
| 222 |
+
def forward(
|
| 223 |
+
self,
|
| 224 |
+
hidden_states: torch.Tensor,
|
| 225 |
+
context: torch.Tensor,
|
| 226 |
+
relative_position_bias: torch.Tensor,
|
| 227 |
+
) -> torch.Tensor:
|
| 228 |
+
for self_attn, cross_attn, ffn in self.layers:
|
| 229 |
+
hidden_states = self_attn(hidden_states, relative_position_bias) + hidden_states
|
| 230 |
+
hidden_states = cross_attn(hidden_states, context, relative_position_bias) + hidden_states
|
| 231 |
+
hidden_states = ffn(hidden_states) + hidden_states
|
| 232 |
+
return self.norm_out(hidden_states)
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
class CromaViTEncoder(nn.Module):
|
| 236 |
+
def __init__(self, config: CromaConfig, depth: int, in_channels: int):
|
| 237 |
+
super().__init__()
|
| 238 |
+
self.patch_size = config.patch_size
|
| 239 |
+
pixels_per_patch = config.patch_size * config.patch_size * in_channels
|
| 240 |
+
self.linear_input = nn.Linear(pixels_per_patch, config.hidden_size)
|
| 241 |
+
self.transformer = CromaEncoder(config, depth=depth)
|
| 242 |
+
|
| 243 |
+
def forward(self, pixel_values: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 244 |
+
hidden_states = rearrange(
|
| 245 |
+
pixel_values,
|
| 246 |
+
"b c (h i) (w j) -> b (h w) (c i j)",
|
| 247 |
+
i=self.patch_size,
|
| 248 |
+
j=self.patch_size,
|
| 249 |
+
)
|
| 250 |
+
hidden_states = self.linear_input(hidden_states)
|
| 251 |
+
return self.transformer(hidden_states, relative_position_bias)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class CromaGapHead(nn.Module):
|
| 255 |
+
def __init__(self, config: CromaConfig):
|
| 256 |
+
super().__init__()
|
| 257 |
+
self.net = nn.Sequential(
|
| 258 |
+
nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps),
|
| 259 |
+
nn.Linear(config.hidden_size, 4 * config.hidden_size),
|
| 260 |
+
nn.GELU(),
|
| 261 |
+
nn.Linear(4 * config.hidden_size, config.hidden_size),
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 265 |
+
return self.net(hidden_states.mean(dim=1))
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
class CromaPreTrainedModel(PreTrainedModel):
|
| 269 |
+
config_class = CromaConfig
|
| 270 |
+
base_model_prefix = "croma"
|
| 271 |
+
main_input_name = "optical_pixel_values"
|
| 272 |
+
input_modalities = ("image",)
|
| 273 |
+
supports_gradient_checkpointing = False
|
| 274 |
+
_no_split_modules = ["CromaEncoder", "CromaCrossEncoder"]
|
| 275 |
+
|
| 276 |
+
def _init_weights(self, module):
|
| 277 |
+
if isinstance(module, nn.Linear):
|
| 278 |
+
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
|
| 279 |
+
if module.bias is not None:
|
| 280 |
+
module.bias.data.zero_()
|
| 281 |
+
elif isinstance(module, nn.LayerNorm):
|
| 282 |
+
module.bias.data.zero_()
|
| 283 |
+
module.weight.data.fill_(1.0)
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
class CromaModel(CromaPreTrainedModel):
|
| 287 |
+
def __init__(self, config: CromaConfig):
|
| 288 |
+
super().__init__(config)
|
| 289 |
+
self.modality = config.modality
|
| 290 |
+
self.register_buffer(
|
| 291 |
+
"attn_bias",
|
| 292 |
+
get_2dalibi(config.num_attention_heads, config.num_patches),
|
| 293 |
+
persistent=False,
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
cross_depth = config.num_hidden_layers // 2
|
| 297 |
+
if config.modality in {"sar", "both"}:
|
| 298 |
+
self.sar_encoder = CromaViTEncoder(config, depth=cross_depth, in_channels=config.sar_channels)
|
| 299 |
+
self.sar_gap_ffn = CromaGapHead(config)
|
| 300 |
+
if config.modality in {"optical", "both"}:
|
| 301 |
+
self.optical_encoder = CromaViTEncoder(
|
| 302 |
+
config, depth=config.num_hidden_layers, in_channels=config.optical_channels
|
| 303 |
+
)
|
| 304 |
+
self.optical_gap_ffn = CromaGapHead(config)
|
| 305 |
+
if config.modality == "both":
|
| 306 |
+
self.cross_encoder = CromaCrossEncoder(config, depth=cross_depth)
|
| 307 |
+
|
| 308 |
+
self.post_init()
|
| 309 |
+
|
| 310 |
+
def _resolve_primary_outputs(
|
| 311 |
+
self,
|
| 312 |
+
sar_hidden_states,
|
| 313 |
+
sar_pooler_output,
|
| 314 |
+
optical_hidden_states,
|
| 315 |
+
optical_pooler_output,
|
| 316 |
+
joint_hidden_states,
|
| 317 |
+
joint_pooler_output,
|
| 318 |
+
):
|
| 319 |
+
if joint_hidden_states is not None:
|
| 320 |
+
return joint_hidden_states, joint_pooler_output
|
| 321 |
+
if self.modality == "sar" or sar_hidden_states is not None:
|
| 322 |
+
return sar_hidden_states, sar_pooler_output
|
| 323 |
+
return optical_hidden_states, optical_pooler_output
|
| 324 |
+
|
| 325 |
+
def forward(
|
| 326 |
+
self,
|
| 327 |
+
sar_pixel_values: Optional[torch.Tensor] = None,
|
| 328 |
+
optical_pixel_values: Optional[torch.Tensor] = None,
|
| 329 |
+
return_dict: Optional[bool] = None,
|
| 330 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 331 |
+
) -> CromaModelOutput:
|
| 332 |
+
if return_dict is None:
|
| 333 |
+
return_dict = self.config.use_return_dict
|
| 334 |
+
|
| 335 |
+
has_sar = sar_pixel_values is not None
|
| 336 |
+
has_optical = optical_pixel_values is not None
|
| 337 |
+
|
| 338 |
+
if self.modality == "both":
|
| 339 |
+
if not has_sar and not has_optical:
|
| 340 |
+
raise ValueError("Provide at least one of `sar_pixel_values` or `optical_pixel_values`.")
|
| 341 |
+
elif self.modality == "sar" and not has_sar:
|
| 342 |
+
raise ValueError("Modality is set to 'sar', but `sar_pixel_values` is None.")
|
| 343 |
+
elif self.modality == "optical" and not has_optical:
|
| 344 |
+
raise ValueError("Modality is set to 'optical', but `optical_pixel_values` is None.")
|
| 345 |
+
|
| 346 |
+
attn_bias = self.attn_bias
|
| 347 |
+
sar_hidden_states = sar_pooler_output = None
|
| 348 |
+
optical_hidden_states = optical_pooler_output = None
|
| 349 |
+
joint_hidden_states = joint_pooler_output = None
|
| 350 |
+
|
| 351 |
+
if self.modality in {"sar", "both"} and has_sar:
|
| 352 |
+
sar_pixel_values = sar_pixel_values.to(dtype=self.dtype)
|
| 353 |
+
attn_bias = attn_bias.to(device=sar_pixel_values.device, dtype=sar_pixel_values.dtype)
|
| 354 |
+
sar_hidden_states = self.sar_encoder(sar_pixel_values, attn_bias)
|
| 355 |
+
sar_pooler_output = self.sar_gap_ffn(sar_hidden_states)
|
| 356 |
+
|
| 357 |
+
if self.modality in {"optical", "both"} and has_optical:
|
| 358 |
+
optical_pixel_values = optical_pixel_values.to(dtype=self.dtype)
|
| 359 |
+
attn_bias = attn_bias.to(device=optical_pixel_values.device, dtype=optical_pixel_values.dtype)
|
| 360 |
+
optical_hidden_states = self.optical_encoder(optical_pixel_values, attn_bias)
|
| 361 |
+
optical_pooler_output = self.optical_gap_ffn(optical_hidden_states)
|
| 362 |
+
|
| 363 |
+
if self.modality == "both" and has_sar and has_optical:
|
| 364 |
+
joint_hidden_states = self.cross_encoder(sar_hidden_states, optical_hidden_states, attn_bias)
|
| 365 |
+
joint_pooler_output = joint_hidden_states.mean(dim=1)
|
| 366 |
+
|
| 367 |
+
last_hidden_state, pooler_output = self._resolve_primary_outputs(
|
| 368 |
+
sar_hidden_states,
|
| 369 |
+
sar_pooler_output,
|
| 370 |
+
optical_hidden_states,
|
| 371 |
+
optical_pooler_output,
|
| 372 |
+
joint_hidden_states,
|
| 373 |
+
joint_pooler_output,
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
if not return_dict:
|
| 377 |
+
return (
|
| 378 |
+
last_hidden_state,
|
| 379 |
+
pooler_output,
|
| 380 |
+
sar_hidden_states,
|
| 381 |
+
sar_pooler_output,
|
| 382 |
+
optical_hidden_states,
|
| 383 |
+
optical_pooler_output,
|
| 384 |
+
joint_hidden_states,
|
| 385 |
+
joint_pooler_output,
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
return CromaModelOutput(
|
| 389 |
+
last_hidden_state=last_hidden_state,
|
| 390 |
+
pooler_output=pooler_output,
|
| 391 |
+
sar_hidden_states=sar_hidden_states,
|
| 392 |
+
sar_pooler_output=sar_pooler_output,
|
| 393 |
+
optical_hidden_states=optical_hidden_states,
|
| 394 |
+
optical_pooler_output=optical_pooler_output,
|
| 395 |
+
joint_hidden_states=joint_hidden_states,
|
| 396 |
+
joint_pooler_output=joint_pooler_output,
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
__all__ = ["CromaConfig", "CromaModel", "CromaModelOutput", "CromaPreTrainedModel"]
|
croma-base-patch8-120/pipeline_croma.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Custom CROMA dual-modality feature extraction pipeline."""
|
| 3 |
+
|
| 4 |
+
from typing import Any, Optional, Union
|
| 5 |
+
|
| 6 |
+
from transformers.image_utils import load_image
|
| 7 |
+
from transformers.pipelines.base import GenericTensor, Pipeline
|
| 8 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class CROMAImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 12 |
+
"""SAR-optical feature extraction for CROMA."""
|
| 13 |
+
|
| 14 |
+
def _sanitize_parameters(
|
| 15 |
+
self,
|
| 16 |
+
image_processor_kwargs=None,
|
| 17 |
+
return_tensors=None,
|
| 18 |
+
pool=None,
|
| 19 |
+
sar_images=None,
|
| 20 |
+
optical_images=None,
|
| 21 |
+
use_8_bit=None,
|
| 22 |
+
output_mode=None,
|
| 23 |
+
**kwargs,
|
| 24 |
+
):
|
| 25 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 26 |
+
|
| 27 |
+
if sar_images is not None:
|
| 28 |
+
preprocess_params["sar_images"] = sar_images
|
| 29 |
+
if optical_images is not None:
|
| 30 |
+
preprocess_params["optical_images"] = optical_images
|
| 31 |
+
if use_8_bit is not None:
|
| 32 |
+
preprocess_params["use_8_bit"] = use_8_bit
|
| 33 |
+
if "timeout" in kwargs:
|
| 34 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 35 |
+
|
| 36 |
+
postprocess_params = {}
|
| 37 |
+
if pool is not None:
|
| 38 |
+
postprocess_params["pool"] = pool
|
| 39 |
+
if return_tensors is not None:
|
| 40 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 41 |
+
if output_mode is not None:
|
| 42 |
+
postprocess_params["output_mode"] = output_mode
|
| 43 |
+
|
| 44 |
+
return preprocess_params, {}, postprocess_params
|
| 45 |
+
|
| 46 |
+
def preprocess(
|
| 47 |
+
self,
|
| 48 |
+
image=None,
|
| 49 |
+
sar_images=None,
|
| 50 |
+
optical_images=None,
|
| 51 |
+
timeout=None,
|
| 52 |
+
**image_processor_kwargs,
|
| 53 |
+
) -> dict[str, GenericTensor]:
|
| 54 |
+
if sar_images is None:
|
| 55 |
+
sar_images = image_processor_kwargs.pop("sar_images", None)
|
| 56 |
+
if optical_images is None:
|
| 57 |
+
optical_images = image_processor_kwargs.pop("optical_images", None)
|
| 58 |
+
|
| 59 |
+
if sar_images is not None and not isinstance(sar_images, (list, tuple)) and not hasattr(sar_images, "shape"):
|
| 60 |
+
sar_images = load_image(sar_images, timeout=timeout)
|
| 61 |
+
if optical_images is not None and not isinstance(optical_images, (list, tuple)) and not hasattr(
|
| 62 |
+
optical_images, "shape"
|
| 63 |
+
):
|
| 64 |
+
optical_images = load_image(optical_images, timeout=timeout)
|
| 65 |
+
if image is not None and optical_images is None and sar_images is None:
|
| 66 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 67 |
+
image = load_image(image, timeout=timeout)
|
| 68 |
+
optical_images = image
|
| 69 |
+
|
| 70 |
+
model_inputs = self.image_processor.preprocess(
|
| 71 |
+
images=optical_images if optical_images is not None else sar_images,
|
| 72 |
+
sar_images=sar_images,
|
| 73 |
+
optical_images=optical_images,
|
| 74 |
+
return_tensors="pt",
|
| 75 |
+
**image_processor_kwargs,
|
| 76 |
+
)
|
| 77 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 78 |
+
return model_inputs
|
| 79 |
+
|
| 80 |
+
def postprocess(self, model_outputs, pool=None, return_tensors=False, output_mode="primary"):
|
| 81 |
+
pool = pool if pool is not None else False
|
| 82 |
+
output_mode = output_mode or "primary"
|
| 83 |
+
|
| 84 |
+
if output_mode == "sar":
|
| 85 |
+
outputs = model_outputs["sar_pooler_output"] if pool else model_outputs["sar_hidden_states"]
|
| 86 |
+
elif output_mode == "optical":
|
| 87 |
+
outputs = model_outputs["optical_pooler_output"] if pool else model_outputs["optical_hidden_states"]
|
| 88 |
+
elif output_mode == "joint":
|
| 89 |
+
outputs = model_outputs["joint_pooler_output"] if pool else model_outputs["joint_hidden_states"]
|
| 90 |
+
elif pool:
|
| 91 |
+
outputs = model_outputs["pooler_output"]
|
| 92 |
+
else:
|
| 93 |
+
outputs = model_outputs[0]
|
| 94 |
+
|
| 95 |
+
if return_tensors:
|
| 96 |
+
return outputs
|
| 97 |
+
return outputs.tolist()
|
| 98 |
+
|
| 99 |
+
def __call__(
|
| 100 |
+
self,
|
| 101 |
+
images: Optional[Union[str, Any, list[Any]]] = None,
|
| 102 |
+
sar_images: Optional[Union[str, Any, list[Any]]] = None,
|
| 103 |
+
optical_images: Optional[Union[str, Any, list[Any]]] = None,
|
| 104 |
+
**kwargs: Any,
|
| 105 |
+
) -> list[Any]:
|
| 106 |
+
if images is None and sar_images is None and optical_images is None:
|
| 107 |
+
raise ValueError("Provide at least one of `images`, `sar_images`, or `optical_images`.")
|
| 108 |
+
|
| 109 |
+
if images is None:
|
| 110 |
+
images = optical_images if optical_images is not None else sar_images
|
| 111 |
+
|
| 112 |
+
return Pipeline.__call__(self, images, sar_images=sar_images, optical_images=optical_images, **kwargs)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
__all__ = ["CROMAImageFeatureExtractionPipeline"]
|
croma-base-patch8-120/preprocessor_config.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "CromaImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 120,
|
| 5 |
+
"width": 120
|
| 6 |
+
},
|
| 7 |
+
"do_resize": true,
|
| 8 |
+
"do_rescale": true,
|
| 9 |
+
"do_normalize": true,
|
| 10 |
+
"use_8_bit": true,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"rescale_factor": 0.00392156862745098,
|
| 13 |
+
"auto_map": {
|
| 14 |
+
"AutoImageProcessor": "image_processing_croma.CromaImageProcessor"
|
| 15 |
+
}
|
| 16 |
+
}
|
croma-large-patch8-120/config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"CromaModel"
|
| 4 |
+
],
|
| 5 |
+
"model_type": "croma",
|
| 6 |
+
"dtype": "float32",
|
| 7 |
+
"transformers_version": "5.0.0",
|
| 8 |
+
"hidden_size": 1024,
|
| 9 |
+
"num_hidden_layers": 24,
|
| 10 |
+
"num_attention_heads": 16,
|
| 11 |
+
"patch_size": 8,
|
| 12 |
+
"image_size": 120,
|
| 13 |
+
"sar_channels": 2,
|
| 14 |
+
"optical_channels": 12,
|
| 15 |
+
"modality": "both",
|
| 16 |
+
"hidden_dropout_prob": 0.0,
|
| 17 |
+
"layer_norm_eps": 1e-05,
|
| 18 |
+
"initializer_range": 0.02,
|
| 19 |
+
"num_patches": 225,
|
| 20 |
+
"auto_map": {
|
| 21 |
+
"AutoConfig": "modeling_croma.CromaConfig",
|
| 22 |
+
"AutoModel": "modeling_croma.CromaModel"
|
| 23 |
+
},
|
| 24 |
+
"custom_pipelines": {
|
| 25 |
+
"croma-feature-extraction": {
|
| 26 |
+
"impl": "pipeline_croma.CROMAImageFeatureExtractionPipeline",
|
| 27 |
+
"pt": [
|
| 28 |
+
"AutoModel"
|
| 29 |
+
]
|
| 30 |
+
}
|
| 31 |
+
}
|
| 32 |
+
}
|
croma-large-patch8-120/image_processing_croma.py
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA 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 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
"""Image processor for CROMA."""
|
| 15 |
+
|
| 16 |
+
from typing import Optional, Union
|
| 17 |
+
|
| 18 |
+
import numpy as np
|
| 19 |
+
|
| 20 |
+
from transformers.image_processing_utils import BaseImageProcessor, BatchFeature, get_size_dict
|
| 21 |
+
from transformers.image_transforms import resize, to_channel_dimension_format
|
| 22 |
+
from transformers.image_utils import (
|
| 23 |
+
ChannelDimension,
|
| 24 |
+
ImageInput,
|
| 25 |
+
PILImageResampling,
|
| 26 |
+
infer_channel_dimension_format,
|
| 27 |
+
make_flat_list_of_images,
|
| 28 |
+
to_numpy_array,
|
| 29 |
+
valid_images,
|
| 30 |
+
validate_preprocess_arguments,
|
| 31 |
+
)
|
| 32 |
+
from transformers.utils import TensorType, filter_out_non_signature_kwargs, logging
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
logger = logging.get_logger(__name__)
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def _resize_multispectral(image: np.ndarray, size: dict[str, int], input_data_format: ChannelDimension) -> np.ndarray:
|
| 39 |
+
target_height, target_width = size["height"], size["width"]
|
| 40 |
+
|
| 41 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 42 |
+
image = np.transpose(image, (1, 2, 0))
|
| 43 |
+
|
| 44 |
+
height, width, _ = image.shape
|
| 45 |
+
if height == target_height and width == target_width:
|
| 46 |
+
resized = image
|
| 47 |
+
else:
|
| 48 |
+
try:
|
| 49 |
+
import cv2
|
| 50 |
+
except ImportError as exc:
|
| 51 |
+
raise ImportError(
|
| 52 |
+
"Multispectral resize requires OpenCV (`opencv-python`) when input has more than 4 channels."
|
| 53 |
+
) from exc
|
| 54 |
+
resized = cv2.resize(image, (target_width, target_height), interpolation=cv2.INTER_LINEAR)
|
| 55 |
+
|
| 56 |
+
if input_data_format == ChannelDimension.FIRST:
|
| 57 |
+
return np.transpose(resized, (2, 0, 1))
|
| 58 |
+
return resized
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def normalize_croma_channels(
|
| 62 |
+
images: np.ndarray,
|
| 63 |
+
input_data_format: ChannelDimension,
|
| 64 |
+
use_8_bit: bool = False,
|
| 65 |
+
) -> np.ndarray:
|
| 66 |
+
"""
|
| 67 |
+
Apply per-channel mean +/- 2*std normalization used by CROMA (SatMAE / SeCo style).
|
| 68 |
+
|
| 69 |
+
Args:
|
| 70 |
+
images (`np.ndarray`):
|
| 71 |
+
Input image array in channels-first or channels-last format.
|
| 72 |
+
input_data_format (`ChannelDimension`):
|
| 73 |
+
Whether channels are first or last.
|
| 74 |
+
use_8_bit (`bool`, *optional*, defaults to `False`):
|
| 75 |
+
If `True`, scale to `[0, 255]` and cast to `uint8`. Otherwise scale to `[0, 1]`.
|
| 76 |
+
"""
|
| 77 |
+
if input_data_format == ChannelDimension.LAST:
|
| 78 |
+
images = np.transpose(images, (2, 0, 1))
|
| 79 |
+
|
| 80 |
+
normalized_channels = []
|
| 81 |
+
for channel in range(images.shape[0]):
|
| 82 |
+
channel_data = images[channel].astype(np.float32)
|
| 83 |
+
min_value = channel_data.mean() - 2 * channel_data.std()
|
| 84 |
+
max_value = channel_data.mean() + 2 * channel_data.std()
|
| 85 |
+
denominator = max_value - min_value
|
| 86 |
+
if denominator == 0:
|
| 87 |
+
denominator = 1.0
|
| 88 |
+
|
| 89 |
+
if use_8_bit:
|
| 90 |
+
channel_data = (channel_data - min_value) / denominator * 255.0
|
| 91 |
+
channel_data = np.clip(channel_data, 0, 255).astype(np.uint8)
|
| 92 |
+
else:
|
| 93 |
+
channel_data = (channel_data - min_value) / denominator
|
| 94 |
+
channel_data = np.clip(channel_data, 0, 1).astype(np.float32)
|
| 95 |
+
|
| 96 |
+
normalized_channels.append(channel_data)
|
| 97 |
+
|
| 98 |
+
normalized = np.stack(normalized_channels, axis=0)
|
| 99 |
+
if input_data_format == ChannelDimension.LAST:
|
| 100 |
+
return np.transpose(normalized, (1, 2, 0))
|
| 101 |
+
return normalized
|
| 102 |
+
|
| 103 |
+
|
| 104 |
+
class CromaImageProcessor(BaseImageProcessor):
|
| 105 |
+
"""
|
| 106 |
+
Image processor for CROMA models.
|
| 107 |
+
|
| 108 |
+
CROMA accepts separate Sentinel-1 SAR (2 channels) and Sentinel-2 optical (12 channels) inputs. The processor
|
| 109 |
+
applies per-channel mean +/- 2*std normalization and optional resizing.
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
model_input_names = ["sar_pixel_values", "optical_pixel_values"]
|
| 113 |
+
|
| 114 |
+
def __init__(
|
| 115 |
+
self,
|
| 116 |
+
do_resize: bool = True,
|
| 117 |
+
size: Optional[dict[str, int]] = None,
|
| 118 |
+
resample: PILImageResampling = PILImageResampling.BILINEAR,
|
| 119 |
+
do_rescale: bool = True,
|
| 120 |
+
rescale_factor: float = 1 / 255.0,
|
| 121 |
+
do_normalize: bool = True,
|
| 122 |
+
use_8_bit: bool = False,
|
| 123 |
+
do_convert_rgb: bool = False,
|
| 124 |
+
**kwargs,
|
| 125 |
+
):
|
| 126 |
+
super().__init__(**kwargs)
|
| 127 |
+
size = size if size is not None else {"height": 120, "width": 120}
|
| 128 |
+
self.do_resize = do_resize
|
| 129 |
+
self.size = size
|
| 130 |
+
self.resample = resample
|
| 131 |
+
self.do_rescale = do_rescale
|
| 132 |
+
self.rescale_factor = rescale_factor
|
| 133 |
+
self.do_normalize = do_normalize
|
| 134 |
+
self.use_8_bit = use_8_bit
|
| 135 |
+
self.do_convert_rgb = do_convert_rgb
|
| 136 |
+
|
| 137 |
+
def _preprocess_modality(
|
| 138 |
+
self,
|
| 139 |
+
images: ImageInput,
|
| 140 |
+
expected_channels: Optional[int],
|
| 141 |
+
do_resize: bool,
|
| 142 |
+
size: dict[str, int],
|
| 143 |
+
resample: PILImageResampling,
|
| 144 |
+
do_rescale: bool,
|
| 145 |
+
rescale_factor: float,
|
| 146 |
+
do_normalize: bool,
|
| 147 |
+
use_8_bit: bool,
|
| 148 |
+
do_convert_rgb: bool,
|
| 149 |
+
data_format: Union[str, ChannelDimension],
|
| 150 |
+
input_data_format: Optional[Union[str, ChannelDimension]],
|
| 151 |
+
) -> list[np.ndarray]:
|
| 152 |
+
images = make_flat_list_of_images(images)
|
| 153 |
+
if not valid_images(images):
|
| 154 |
+
raise ValueError("Invalid image type. Must be PIL, numpy, or torch tensor.")
|
| 155 |
+
|
| 156 |
+
processed_images = []
|
| 157 |
+
for image in images:
|
| 158 |
+
image = to_numpy_array(image)
|
| 159 |
+
if do_convert_rgb:
|
| 160 |
+
image = self._convert_image_to_rgb(image)
|
| 161 |
+
|
| 162 |
+
if input_data_format is None:
|
| 163 |
+
if isinstance(image, np.ndarray) and image.ndim == 3:
|
| 164 |
+
# CROMA expects channels-first tensors; prefer FIRST when the leading axis looks like channels.
|
| 165 |
+
current_input_format = (
|
| 166 |
+
ChannelDimension.FIRST if image.shape[0] <= image.shape[-1] else ChannelDimension.LAST
|
| 167 |
+
)
|
| 168 |
+
else:
|
| 169 |
+
try:
|
| 170 |
+
current_input_format = infer_channel_dimension_format(image)
|
| 171 |
+
except ValueError:
|
| 172 |
+
current_input_format = ChannelDimension.LAST
|
| 173 |
+
else:
|
| 174 |
+
current_input_format = input_data_format
|
| 175 |
+
|
| 176 |
+
num_channels = image.shape[-1] if current_input_format == ChannelDimension.LAST else image.shape[0]
|
| 177 |
+
if expected_channels is not None and num_channels != expected_channels:
|
| 178 |
+
raise ValueError(
|
| 179 |
+
f"Expected {expected_channels} channels for this modality, but got {num_channels}."
|
| 180 |
+
)
|
| 181 |
+
|
| 182 |
+
if do_normalize:
|
| 183 |
+
image = normalize_croma_channels(
|
| 184 |
+
image,
|
| 185 |
+
input_data_format=current_input_format,
|
| 186 |
+
use_8_bit=use_8_bit,
|
| 187 |
+
)
|
| 188 |
+
if use_8_bit and do_rescale:
|
| 189 |
+
image = image.astype(np.float32) / 255.0
|
| 190 |
+
elif do_rescale:
|
| 191 |
+
image = image * rescale_factor
|
| 192 |
+
|
| 193 |
+
if do_resize:
|
| 194 |
+
if num_channels != 3:
|
| 195 |
+
image = _resize_multispectral(image, size=size, input_data_format=current_input_format)
|
| 196 |
+
else:
|
| 197 |
+
image = resize(image, size=size, resample=resample, input_data_format=current_input_format)
|
| 198 |
+
|
| 199 |
+
image = to_channel_dimension_format(image, data_format, input_channel_dim=current_input_format)
|
| 200 |
+
processed_images.append(image)
|
| 201 |
+
|
| 202 |
+
return processed_images
|
| 203 |
+
|
| 204 |
+
@filter_out_non_signature_kwargs()
|
| 205 |
+
def preprocess(
|
| 206 |
+
self,
|
| 207 |
+
images: Optional[ImageInput] = None,
|
| 208 |
+
sar_images: Optional[ImageInput] = None,
|
| 209 |
+
optical_images: Optional[ImageInput] = None,
|
| 210 |
+
do_resize: Optional[bool] = None,
|
| 211 |
+
size: Optional[dict[str, int]] = None,
|
| 212 |
+
resample: Optional[PILImageResampling] = None,
|
| 213 |
+
do_rescale: Optional[bool] = None,
|
| 214 |
+
rescale_factor: Optional[float] = None,
|
| 215 |
+
do_normalize: Optional[bool] = None,
|
| 216 |
+
use_8_bit: Optional[bool] = None,
|
| 217 |
+
return_tensors: Optional[Union[str, TensorType]] = None,
|
| 218 |
+
data_format: Union[str, ChannelDimension] = ChannelDimension.FIRST,
|
| 219 |
+
input_data_format: Optional[Union[str, ChannelDimension]] = None,
|
| 220 |
+
do_convert_rgb: Optional[bool] = None,
|
| 221 |
+
):
|
| 222 |
+
do_resize = do_resize if do_resize is not None else self.do_resize
|
| 223 |
+
size = size if size is not None else self.size
|
| 224 |
+
size = get_size_dict(size, default_to_square=True)
|
| 225 |
+
resample = resample if resample is not None else self.resample
|
| 226 |
+
do_rescale = do_rescale if do_rescale is not None else self.do_rescale
|
| 227 |
+
rescale_factor = rescale_factor if rescale_factor is not None else self.rescale_factor
|
| 228 |
+
do_normalize = do_normalize if do_normalize is not None else self.do_normalize
|
| 229 |
+
use_8_bit = use_8_bit if use_8_bit is not None else self.use_8_bit
|
| 230 |
+
do_convert_rgb = do_convert_rgb if do_convert_rgb is not None else self.do_convert_rgb
|
| 231 |
+
|
| 232 |
+
validate_preprocess_arguments(
|
| 233 |
+
do_rescale=do_rescale,
|
| 234 |
+
rescale_factor=rescale_factor,
|
| 235 |
+
do_normalize=False,
|
| 236 |
+
do_resize=do_resize,
|
| 237 |
+
size=size,
|
| 238 |
+
resample=resample,
|
| 239 |
+
)
|
| 240 |
+
|
| 241 |
+
if sar_images is None and optical_images is None:
|
| 242 |
+
if images is None:
|
| 243 |
+
raise ValueError("Provide `sar_images`, `optical_images`, or legacy `images` for preprocessing.")
|
| 244 |
+
optical_images = images
|
| 245 |
+
|
| 246 |
+
data = {}
|
| 247 |
+
if sar_images is not None:
|
| 248 |
+
data["sar_pixel_values"] = self._preprocess_modality(
|
| 249 |
+
sar_images,
|
| 250 |
+
expected_channels=2,
|
| 251 |
+
do_resize=do_resize,
|
| 252 |
+
size=size,
|
| 253 |
+
resample=resample,
|
| 254 |
+
do_rescale=do_rescale,
|
| 255 |
+
rescale_factor=rescale_factor,
|
| 256 |
+
do_normalize=do_normalize,
|
| 257 |
+
use_8_bit=use_8_bit,
|
| 258 |
+
do_convert_rgb=do_convert_rgb,
|
| 259 |
+
data_format=data_format,
|
| 260 |
+
input_data_format=input_data_format,
|
| 261 |
+
)
|
| 262 |
+
if optical_images is not None:
|
| 263 |
+
data["optical_pixel_values"] = self._preprocess_modality(
|
| 264 |
+
optical_images,
|
| 265 |
+
expected_channels=12,
|
| 266 |
+
do_resize=do_resize,
|
| 267 |
+
size=size,
|
| 268 |
+
resample=resample,
|
| 269 |
+
do_rescale=do_rescale,
|
| 270 |
+
rescale_factor=rescale_factor,
|
| 271 |
+
do_normalize=do_normalize,
|
| 272 |
+
use_8_bit=use_8_bit,
|
| 273 |
+
do_convert_rgb=do_convert_rgb,
|
| 274 |
+
data_format=data_format,
|
| 275 |
+
input_data_format=input_data_format,
|
| 276 |
+
)
|
| 277 |
+
|
| 278 |
+
return BatchFeature(data=data, tensor_type=return_tensors)
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
__all__ = ["CromaImageProcessor", "normalize_croma_channels"]
|
croma-large-patch8-120/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9f715dddabd7219b84c8d856b8496d9cb3f2dbec46f9ab6967078cbed44c614e
|
| 3 |
+
size 2690304360
|
croma-large-patch8-120/modeling_croma.py
ADDED
|
@@ -0,0 +1,400 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Self-contained CROMA model and configuration."""
|
| 3 |
+
|
| 4 |
+
from __future__ import annotations
|
| 5 |
+
|
| 6 |
+
import itertools
|
| 7 |
+
import math
|
| 8 |
+
from dataclasses import dataclass
|
| 9 |
+
from typing import Optional
|
| 10 |
+
|
| 11 |
+
import torch
|
| 12 |
+
from einops import rearrange
|
| 13 |
+
from torch import einsum, nn
|
| 14 |
+
|
| 15 |
+
from transformers.configuration_utils import PretrainedConfig as PreTrainedConfig
|
| 16 |
+
from transformers.modeling_outputs import BaseModelOutputWithPooling
|
| 17 |
+
from transformers.modeling_utils import PreTrainedModel
|
| 18 |
+
from transformers.processing_utils import Unpack
|
| 19 |
+
from transformers.utils import TransformersKwargs, logging
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
logger = logging.get_logger(__name__)
|
| 23 |
+
|
| 24 |
+
|
| 25 |
+
class CromaConfig(PreTrainedConfig):
|
| 26 |
+
model_type = "croma"
|
| 27 |
+
|
| 28 |
+
def __init__(
|
| 29 |
+
self,
|
| 30 |
+
hidden_size=768,
|
| 31 |
+
num_hidden_layers=12,
|
| 32 |
+
num_attention_heads=16,
|
| 33 |
+
patch_size=8,
|
| 34 |
+
image_size=120,
|
| 35 |
+
sar_channels=2,
|
| 36 |
+
optical_channels=12,
|
| 37 |
+
modality="both",
|
| 38 |
+
hidden_dropout_prob=0.0,
|
| 39 |
+
layer_norm_eps=1e-5,
|
| 40 |
+
initializer_range=0.02,
|
| 41 |
+
num_patches=None,
|
| 42 |
+
**kwargs,
|
| 43 |
+
):
|
| 44 |
+
super().__init__(**kwargs)
|
| 45 |
+
|
| 46 |
+
if image_size % patch_size != 0:
|
| 47 |
+
raise ValueError(f"`image_size` ({image_size}) must be divisible by `patch_size` ({patch_size}).")
|
| 48 |
+
|
| 49 |
+
if modality not in {"both", "sar", "optical"}:
|
| 50 |
+
raise ValueError(f"`modality` must be one of 'both', 'sar', or 'optical', got {modality!r}.")
|
| 51 |
+
|
| 52 |
+
self.hidden_size = hidden_size
|
| 53 |
+
self.num_hidden_layers = num_hidden_layers
|
| 54 |
+
self.num_attention_heads = num_attention_heads
|
| 55 |
+
self.patch_size = patch_size
|
| 56 |
+
self.image_size = image_size
|
| 57 |
+
self.sar_channels = sar_channels
|
| 58 |
+
self.optical_channels = optical_channels
|
| 59 |
+
self.modality = modality
|
| 60 |
+
self.hidden_dropout_prob = hidden_dropout_prob
|
| 61 |
+
self.layer_norm_eps = layer_norm_eps
|
| 62 |
+
self.initializer_range = initializer_range
|
| 63 |
+
self.num_patches = num_patches if num_patches is not None else (image_size // patch_size) ** 2
|
| 64 |
+
|
| 65 |
+
|
| 66 |
+
def get_2dalibi(num_heads: int, num_patches: int) -> torch.Tensor:
|
| 67 |
+
grid_size = int(math.sqrt(num_patches))
|
| 68 |
+
points = list(itertools.product(range(grid_size), range(grid_size)))
|
| 69 |
+
|
| 70 |
+
def get_slopes(n):
|
| 71 |
+
def get_slopes_power_of_2(n):
|
| 72 |
+
start = 2 ** (-2 ** -(math.log2(n) - 3))
|
| 73 |
+
ratio = start
|
| 74 |
+
return [start * ratio**i for i in range(n)]
|
| 75 |
+
|
| 76 |
+
if math.log2(n).is_integer():
|
| 77 |
+
return get_slopes_power_of_2(n)
|
| 78 |
+
closest_power_of_2 = 2 ** math.floor(math.log2(n))
|
| 79 |
+
return get_slopes_power_of_2(closest_power_of_2) + get_slopes(2 * closest_power_of_2)[0::2][
|
| 80 |
+
: n - closest_power_of_2
|
| 81 |
+
]
|
| 82 |
+
|
| 83 |
+
slopes = torch.tensor(get_slopes(num_heads), dtype=torch.float32).unsqueeze(1)
|
| 84 |
+
idxs = []
|
| 85 |
+
for p1 in points:
|
| 86 |
+
for p2 in points:
|
| 87 |
+
dist = math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
| 88 |
+
idxs.append(dist * slopes * -1)
|
| 89 |
+
all_bias = torch.cat(idxs, dim=1)
|
| 90 |
+
return all_bias.view(1, num_heads, num_patches, num_patches)
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
@dataclass
|
| 94 |
+
class CromaModelOutput(BaseModelOutputWithPooling):
|
| 95 |
+
sar_hidden_states: Optional[torch.FloatTensor] = None
|
| 96 |
+
sar_pooler_output: Optional[torch.FloatTensor] = None
|
| 97 |
+
optical_hidden_states: Optional[torch.FloatTensor] = None
|
| 98 |
+
optical_pooler_output: Optional[torch.FloatTensor] = None
|
| 99 |
+
joint_hidden_states: Optional[torch.FloatTensor] = None
|
| 100 |
+
joint_pooler_output: Optional[torch.FloatTensor] = None
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
class CromaFeedForward(nn.Module):
|
| 104 |
+
def __init__(self, config: CromaConfig, mult: int = 4):
|
| 105 |
+
super().__init__()
|
| 106 |
+
inner_dim = int(config.hidden_size * mult)
|
| 107 |
+
self.net = nn.Sequential(
|
| 108 |
+
nn.Linear(config.hidden_size, inner_dim),
|
| 109 |
+
nn.GELU(),
|
| 110 |
+
nn.Dropout(config.hidden_dropout_prob),
|
| 111 |
+
nn.Linear(inner_dim, config.hidden_size),
|
| 112 |
+
)
|
| 113 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 114 |
+
|
| 115 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 116 |
+
hidden_states = self.input_norm(hidden_states)
|
| 117 |
+
return self.net(hidden_states)
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
class CromaAttention(nn.Module):
|
| 121 |
+
def __init__(self, config: CromaConfig):
|
| 122 |
+
super().__init__()
|
| 123 |
+
self.num_attention_heads = config.num_attention_heads
|
| 124 |
+
self.attention_head_size = config.hidden_size // config.num_attention_heads
|
| 125 |
+
self.scale = self.attention_head_size**-0.5
|
| 126 |
+
|
| 127 |
+
self.to_qkv = nn.Linear(config.hidden_size, config.hidden_size * 3, bias=False)
|
| 128 |
+
self.to_out = nn.Linear(config.hidden_size, config.hidden_size)
|
| 129 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 130 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 131 |
+
|
| 132 |
+
def forward(self, hidden_states: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 133 |
+
hidden_states = self.input_norm(hidden_states)
|
| 134 |
+
query, key, value = self.to_qkv(hidden_states).chunk(3, dim=-1)
|
| 135 |
+
query, key, value = map(
|
| 136 |
+
lambda tensor: rearrange(tensor, "b n (h d) -> b h n d", h=self.num_attention_heads),
|
| 137 |
+
(query, key, value),
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
attention_scores = einsum("b h i d, b h j d -> b h i j", query, key) * self.scale
|
| 141 |
+
attention_scores = attention_scores + relative_position_bias
|
| 142 |
+
attention_probs = attention_scores.softmax(dim=-1)
|
| 143 |
+
attention_probs = self.dropout(attention_probs)
|
| 144 |
+
|
| 145 |
+
context = einsum("b h i j, b h j d -> b h i d", attention_probs, value)
|
| 146 |
+
context = rearrange(context, "b h n d -> b n (h d)")
|
| 147 |
+
return self.to_out(context)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
class CromaCrossAttention(nn.Module):
|
| 151 |
+
def __init__(self, config: CromaConfig):
|
| 152 |
+
super().__init__()
|
| 153 |
+
self.num_attention_heads = config.num_attention_heads
|
| 154 |
+
self.attention_head_size = config.hidden_size // config.num_attention_heads
|
| 155 |
+
self.scale = self.attention_head_size**-0.5
|
| 156 |
+
|
| 157 |
+
self.to_q = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 158 |
+
self.to_k = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 159 |
+
self.to_v = nn.Linear(config.hidden_size, config.hidden_size, bias=False)
|
| 160 |
+
self.to_out = nn.Linear(config.hidden_size, config.hidden_size)
|
| 161 |
+
self.input_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 162 |
+
self.dropout = nn.Dropout(config.hidden_dropout_prob)
|
| 163 |
+
|
| 164 |
+
def forward(
|
| 165 |
+
self,
|
| 166 |
+
hidden_states: torch.Tensor,
|
| 167 |
+
context: torch.Tensor,
|
| 168 |
+
relative_position_bias: torch.Tensor,
|
| 169 |
+
) -> torch.Tensor:
|
| 170 |
+
hidden_states = self.input_norm(hidden_states)
|
| 171 |
+
context = self.input_norm(context)
|
| 172 |
+
|
| 173 |
+
query = self.to_q(hidden_states)
|
| 174 |
+
key = self.to_k(context)
|
| 175 |
+
value = self.to_v(context)
|
| 176 |
+
query, key, value = map(
|
| 177 |
+
lambda tensor: rearrange(tensor, "b n (h d) -> b h n d", h=self.num_attention_heads),
|
| 178 |
+
(query, key, value),
|
| 179 |
+
)
|
| 180 |
+
|
| 181 |
+
attention_scores = einsum("b h i d, b h j d -> b h i j", query, key) * self.scale
|
| 182 |
+
attention_scores = attention_scores + relative_position_bias
|
| 183 |
+
attention_probs = attention_scores.softmax(dim=-1)
|
| 184 |
+
attention_probs = self.dropout(attention_probs)
|
| 185 |
+
|
| 186 |
+
context = einsum("b h i j, b h j d -> b h i d", attention_probs, value)
|
| 187 |
+
context = rearrange(context, "b h n d -> b n (h d)")
|
| 188 |
+
return self.to_out(context)
|
| 189 |
+
|
| 190 |
+
|
| 191 |
+
class CromaEncoder(nn.Module):
|
| 192 |
+
def __init__(self, config: CromaConfig, depth: int, final_norm: bool = True):
|
| 193 |
+
super().__init__()
|
| 194 |
+
self.layers = nn.ModuleList(
|
| 195 |
+
[
|
| 196 |
+
nn.ModuleList([CromaAttention(config), CromaFeedForward(config)])
|
| 197 |
+
for _ in range(depth)
|
| 198 |
+
]
|
| 199 |
+
)
|
| 200 |
+
self.norm_out = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps) if final_norm else None
|
| 201 |
+
|
| 202 |
+
def forward(self, hidden_states: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 203 |
+
for self_attn, ffn in self.layers:
|
| 204 |
+
hidden_states = self_attn(hidden_states, relative_position_bias) + hidden_states
|
| 205 |
+
hidden_states = ffn(hidden_states) + hidden_states
|
| 206 |
+
if self.norm_out is not None:
|
| 207 |
+
return self.norm_out(hidden_states)
|
| 208 |
+
return hidden_states
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
class CromaCrossEncoder(nn.Module):
|
| 212 |
+
def __init__(self, config: CromaConfig, depth: int):
|
| 213 |
+
super().__init__()
|
| 214 |
+
self.layers = nn.ModuleList(
|
| 215 |
+
[
|
| 216 |
+
nn.ModuleList([CromaAttention(config), CromaCrossAttention(config), CromaFeedForward(config)])
|
| 217 |
+
for _ in range(depth)
|
| 218 |
+
]
|
| 219 |
+
)
|
| 220 |
+
self.norm_out = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
|
| 221 |
+
|
| 222 |
+
def forward(
|
| 223 |
+
self,
|
| 224 |
+
hidden_states: torch.Tensor,
|
| 225 |
+
context: torch.Tensor,
|
| 226 |
+
relative_position_bias: torch.Tensor,
|
| 227 |
+
) -> torch.Tensor:
|
| 228 |
+
for self_attn, cross_attn, ffn in self.layers:
|
| 229 |
+
hidden_states = self_attn(hidden_states, relative_position_bias) + hidden_states
|
| 230 |
+
hidden_states = cross_attn(hidden_states, context, relative_position_bias) + hidden_states
|
| 231 |
+
hidden_states = ffn(hidden_states) + hidden_states
|
| 232 |
+
return self.norm_out(hidden_states)
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
class CromaViTEncoder(nn.Module):
|
| 236 |
+
def __init__(self, config: CromaConfig, depth: int, in_channels: int):
|
| 237 |
+
super().__init__()
|
| 238 |
+
self.patch_size = config.patch_size
|
| 239 |
+
pixels_per_patch = config.patch_size * config.patch_size * in_channels
|
| 240 |
+
self.linear_input = nn.Linear(pixels_per_patch, config.hidden_size)
|
| 241 |
+
self.transformer = CromaEncoder(config, depth=depth)
|
| 242 |
+
|
| 243 |
+
def forward(self, pixel_values: torch.Tensor, relative_position_bias: torch.Tensor) -> torch.Tensor:
|
| 244 |
+
hidden_states = rearrange(
|
| 245 |
+
pixel_values,
|
| 246 |
+
"b c (h i) (w j) -> b (h w) (c i j)",
|
| 247 |
+
i=self.patch_size,
|
| 248 |
+
j=self.patch_size,
|
| 249 |
+
)
|
| 250 |
+
hidden_states = self.linear_input(hidden_states)
|
| 251 |
+
return self.transformer(hidden_states, relative_position_bias)
|
| 252 |
+
|
| 253 |
+
|
| 254 |
+
class CromaGapHead(nn.Module):
|
| 255 |
+
def __init__(self, config: CromaConfig):
|
| 256 |
+
super().__init__()
|
| 257 |
+
self.net = nn.Sequential(
|
| 258 |
+
nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps),
|
| 259 |
+
nn.Linear(config.hidden_size, 4 * config.hidden_size),
|
| 260 |
+
nn.GELU(),
|
| 261 |
+
nn.Linear(4 * config.hidden_size, config.hidden_size),
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
|
| 265 |
+
return self.net(hidden_states.mean(dim=1))
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
class CromaPreTrainedModel(PreTrainedModel):
|
| 269 |
+
config_class = CromaConfig
|
| 270 |
+
base_model_prefix = "croma"
|
| 271 |
+
main_input_name = "optical_pixel_values"
|
| 272 |
+
input_modalities = ("image",)
|
| 273 |
+
supports_gradient_checkpointing = False
|
| 274 |
+
_no_split_modules = ["CromaEncoder", "CromaCrossEncoder"]
|
| 275 |
+
|
| 276 |
+
def _init_weights(self, module):
|
| 277 |
+
if isinstance(module, nn.Linear):
|
| 278 |
+
module.weight.data.normal_(mean=0.0, std=self.config.initializer_range)
|
| 279 |
+
if module.bias is not None:
|
| 280 |
+
module.bias.data.zero_()
|
| 281 |
+
elif isinstance(module, nn.LayerNorm):
|
| 282 |
+
module.bias.data.zero_()
|
| 283 |
+
module.weight.data.fill_(1.0)
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
class CromaModel(CromaPreTrainedModel):
|
| 287 |
+
def __init__(self, config: CromaConfig):
|
| 288 |
+
super().__init__(config)
|
| 289 |
+
self.modality = config.modality
|
| 290 |
+
self.register_buffer(
|
| 291 |
+
"attn_bias",
|
| 292 |
+
get_2dalibi(config.num_attention_heads, config.num_patches),
|
| 293 |
+
persistent=False,
|
| 294 |
+
)
|
| 295 |
+
|
| 296 |
+
cross_depth = config.num_hidden_layers // 2
|
| 297 |
+
if config.modality in {"sar", "both"}:
|
| 298 |
+
self.sar_encoder = CromaViTEncoder(config, depth=cross_depth, in_channels=config.sar_channels)
|
| 299 |
+
self.sar_gap_ffn = CromaGapHead(config)
|
| 300 |
+
if config.modality in {"optical", "both"}:
|
| 301 |
+
self.optical_encoder = CromaViTEncoder(
|
| 302 |
+
config, depth=config.num_hidden_layers, in_channels=config.optical_channels
|
| 303 |
+
)
|
| 304 |
+
self.optical_gap_ffn = CromaGapHead(config)
|
| 305 |
+
if config.modality == "both":
|
| 306 |
+
self.cross_encoder = CromaCrossEncoder(config, depth=cross_depth)
|
| 307 |
+
|
| 308 |
+
self.post_init()
|
| 309 |
+
|
| 310 |
+
def _resolve_primary_outputs(
|
| 311 |
+
self,
|
| 312 |
+
sar_hidden_states,
|
| 313 |
+
sar_pooler_output,
|
| 314 |
+
optical_hidden_states,
|
| 315 |
+
optical_pooler_output,
|
| 316 |
+
joint_hidden_states,
|
| 317 |
+
joint_pooler_output,
|
| 318 |
+
):
|
| 319 |
+
if joint_hidden_states is not None:
|
| 320 |
+
return joint_hidden_states, joint_pooler_output
|
| 321 |
+
if self.modality == "sar" or sar_hidden_states is not None:
|
| 322 |
+
return sar_hidden_states, sar_pooler_output
|
| 323 |
+
return optical_hidden_states, optical_pooler_output
|
| 324 |
+
|
| 325 |
+
def forward(
|
| 326 |
+
self,
|
| 327 |
+
sar_pixel_values: Optional[torch.Tensor] = None,
|
| 328 |
+
optical_pixel_values: Optional[torch.Tensor] = None,
|
| 329 |
+
return_dict: Optional[bool] = None,
|
| 330 |
+
**kwargs: Unpack[TransformersKwargs],
|
| 331 |
+
) -> CromaModelOutput:
|
| 332 |
+
if return_dict is None:
|
| 333 |
+
return_dict = self.config.use_return_dict
|
| 334 |
+
|
| 335 |
+
has_sar = sar_pixel_values is not None
|
| 336 |
+
has_optical = optical_pixel_values is not None
|
| 337 |
+
|
| 338 |
+
if self.modality == "both":
|
| 339 |
+
if not has_sar and not has_optical:
|
| 340 |
+
raise ValueError("Provide at least one of `sar_pixel_values` or `optical_pixel_values`.")
|
| 341 |
+
elif self.modality == "sar" and not has_sar:
|
| 342 |
+
raise ValueError("Modality is set to 'sar', but `sar_pixel_values` is None.")
|
| 343 |
+
elif self.modality == "optical" and not has_optical:
|
| 344 |
+
raise ValueError("Modality is set to 'optical', but `optical_pixel_values` is None.")
|
| 345 |
+
|
| 346 |
+
attn_bias = self.attn_bias
|
| 347 |
+
sar_hidden_states = sar_pooler_output = None
|
| 348 |
+
optical_hidden_states = optical_pooler_output = None
|
| 349 |
+
joint_hidden_states = joint_pooler_output = None
|
| 350 |
+
|
| 351 |
+
if self.modality in {"sar", "both"} and has_sar:
|
| 352 |
+
sar_pixel_values = sar_pixel_values.to(dtype=self.dtype)
|
| 353 |
+
attn_bias = attn_bias.to(device=sar_pixel_values.device, dtype=sar_pixel_values.dtype)
|
| 354 |
+
sar_hidden_states = self.sar_encoder(sar_pixel_values, attn_bias)
|
| 355 |
+
sar_pooler_output = self.sar_gap_ffn(sar_hidden_states)
|
| 356 |
+
|
| 357 |
+
if self.modality in {"optical", "both"} and has_optical:
|
| 358 |
+
optical_pixel_values = optical_pixel_values.to(dtype=self.dtype)
|
| 359 |
+
attn_bias = attn_bias.to(device=optical_pixel_values.device, dtype=optical_pixel_values.dtype)
|
| 360 |
+
optical_hidden_states = self.optical_encoder(optical_pixel_values, attn_bias)
|
| 361 |
+
optical_pooler_output = self.optical_gap_ffn(optical_hidden_states)
|
| 362 |
+
|
| 363 |
+
if self.modality == "both" and has_sar and has_optical:
|
| 364 |
+
joint_hidden_states = self.cross_encoder(sar_hidden_states, optical_hidden_states, attn_bias)
|
| 365 |
+
joint_pooler_output = joint_hidden_states.mean(dim=1)
|
| 366 |
+
|
| 367 |
+
last_hidden_state, pooler_output = self._resolve_primary_outputs(
|
| 368 |
+
sar_hidden_states,
|
| 369 |
+
sar_pooler_output,
|
| 370 |
+
optical_hidden_states,
|
| 371 |
+
optical_pooler_output,
|
| 372 |
+
joint_hidden_states,
|
| 373 |
+
joint_pooler_output,
|
| 374 |
+
)
|
| 375 |
+
|
| 376 |
+
if not return_dict:
|
| 377 |
+
return (
|
| 378 |
+
last_hidden_state,
|
| 379 |
+
pooler_output,
|
| 380 |
+
sar_hidden_states,
|
| 381 |
+
sar_pooler_output,
|
| 382 |
+
optical_hidden_states,
|
| 383 |
+
optical_pooler_output,
|
| 384 |
+
joint_hidden_states,
|
| 385 |
+
joint_pooler_output,
|
| 386 |
+
)
|
| 387 |
+
|
| 388 |
+
return CromaModelOutput(
|
| 389 |
+
last_hidden_state=last_hidden_state,
|
| 390 |
+
pooler_output=pooler_output,
|
| 391 |
+
sar_hidden_states=sar_hidden_states,
|
| 392 |
+
sar_pooler_output=sar_pooler_output,
|
| 393 |
+
optical_hidden_states=optical_hidden_states,
|
| 394 |
+
optical_pooler_output=optical_pooler_output,
|
| 395 |
+
joint_hidden_states=joint_hidden_states,
|
| 396 |
+
joint_pooler_output=joint_pooler_output,
|
| 397 |
+
)
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
__all__ = ["CromaConfig", "CromaModel", "CromaModelOutput", "CromaPreTrainedModel"]
|
croma-large-patch8-120/pipeline_croma.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2023 The CROMA Authors and The HuggingFace Inc. team.
|
| 2 |
+
"""Custom CROMA dual-modality feature extraction pipeline."""
|
| 3 |
+
|
| 4 |
+
from typing import Any, Optional, Union
|
| 5 |
+
|
| 6 |
+
from transformers.image_utils import load_image
|
| 7 |
+
from transformers.pipelines.base import GenericTensor, Pipeline
|
| 8 |
+
from transformers.pipelines.image_feature_extraction import ImageFeatureExtractionPipeline
|
| 9 |
+
|
| 10 |
+
|
| 11 |
+
class CROMAImageFeatureExtractionPipeline(ImageFeatureExtractionPipeline):
|
| 12 |
+
"""SAR-optical feature extraction for CROMA."""
|
| 13 |
+
|
| 14 |
+
def _sanitize_parameters(
|
| 15 |
+
self,
|
| 16 |
+
image_processor_kwargs=None,
|
| 17 |
+
return_tensors=None,
|
| 18 |
+
pool=None,
|
| 19 |
+
sar_images=None,
|
| 20 |
+
optical_images=None,
|
| 21 |
+
use_8_bit=None,
|
| 22 |
+
output_mode=None,
|
| 23 |
+
**kwargs,
|
| 24 |
+
):
|
| 25 |
+
preprocess_params = {} if image_processor_kwargs is None else dict(image_processor_kwargs)
|
| 26 |
+
|
| 27 |
+
if sar_images is not None:
|
| 28 |
+
preprocess_params["sar_images"] = sar_images
|
| 29 |
+
if optical_images is not None:
|
| 30 |
+
preprocess_params["optical_images"] = optical_images
|
| 31 |
+
if use_8_bit is not None:
|
| 32 |
+
preprocess_params["use_8_bit"] = use_8_bit
|
| 33 |
+
if "timeout" in kwargs:
|
| 34 |
+
preprocess_params["timeout"] = kwargs["timeout"]
|
| 35 |
+
|
| 36 |
+
postprocess_params = {}
|
| 37 |
+
if pool is not None:
|
| 38 |
+
postprocess_params["pool"] = pool
|
| 39 |
+
if return_tensors is not None:
|
| 40 |
+
postprocess_params["return_tensors"] = return_tensors
|
| 41 |
+
if output_mode is not None:
|
| 42 |
+
postprocess_params["output_mode"] = output_mode
|
| 43 |
+
|
| 44 |
+
return preprocess_params, {}, postprocess_params
|
| 45 |
+
|
| 46 |
+
def preprocess(
|
| 47 |
+
self,
|
| 48 |
+
image=None,
|
| 49 |
+
sar_images=None,
|
| 50 |
+
optical_images=None,
|
| 51 |
+
timeout=None,
|
| 52 |
+
**image_processor_kwargs,
|
| 53 |
+
) -> dict[str, GenericTensor]:
|
| 54 |
+
if sar_images is None:
|
| 55 |
+
sar_images = image_processor_kwargs.pop("sar_images", None)
|
| 56 |
+
if optical_images is None:
|
| 57 |
+
optical_images = image_processor_kwargs.pop("optical_images", None)
|
| 58 |
+
|
| 59 |
+
if sar_images is not None and not isinstance(sar_images, (list, tuple)) and not hasattr(sar_images, "shape"):
|
| 60 |
+
sar_images = load_image(sar_images, timeout=timeout)
|
| 61 |
+
if optical_images is not None and not isinstance(optical_images, (list, tuple)) and not hasattr(
|
| 62 |
+
optical_images, "shape"
|
| 63 |
+
):
|
| 64 |
+
optical_images = load_image(optical_images, timeout=timeout)
|
| 65 |
+
if image is not None and optical_images is None and sar_images is None:
|
| 66 |
+
if not isinstance(image, (list, tuple)) and not hasattr(image, "shape"):
|
| 67 |
+
image = load_image(image, timeout=timeout)
|
| 68 |
+
optical_images = image
|
| 69 |
+
|
| 70 |
+
model_inputs = self.image_processor.preprocess(
|
| 71 |
+
images=optical_images if optical_images is not None else sar_images,
|
| 72 |
+
sar_images=sar_images,
|
| 73 |
+
optical_images=optical_images,
|
| 74 |
+
return_tensors="pt",
|
| 75 |
+
**image_processor_kwargs,
|
| 76 |
+
)
|
| 77 |
+
model_inputs = model_inputs.to(self.dtype)
|
| 78 |
+
return model_inputs
|
| 79 |
+
|
| 80 |
+
def postprocess(self, model_outputs, pool=None, return_tensors=False, output_mode="primary"):
|
| 81 |
+
pool = pool if pool is not None else False
|
| 82 |
+
output_mode = output_mode or "primary"
|
| 83 |
+
|
| 84 |
+
if output_mode == "sar":
|
| 85 |
+
outputs = model_outputs["sar_pooler_output"] if pool else model_outputs["sar_hidden_states"]
|
| 86 |
+
elif output_mode == "optical":
|
| 87 |
+
outputs = model_outputs["optical_pooler_output"] if pool else model_outputs["optical_hidden_states"]
|
| 88 |
+
elif output_mode == "joint":
|
| 89 |
+
outputs = model_outputs["joint_pooler_output"] if pool else model_outputs["joint_hidden_states"]
|
| 90 |
+
elif pool:
|
| 91 |
+
outputs = model_outputs["pooler_output"]
|
| 92 |
+
else:
|
| 93 |
+
outputs = model_outputs[0]
|
| 94 |
+
|
| 95 |
+
if return_tensors:
|
| 96 |
+
return outputs
|
| 97 |
+
return outputs.tolist()
|
| 98 |
+
|
| 99 |
+
def __call__(
|
| 100 |
+
self,
|
| 101 |
+
images: Optional[Union[str, Any, list[Any]]] = None,
|
| 102 |
+
sar_images: Optional[Union[str, Any, list[Any]]] = None,
|
| 103 |
+
optical_images: Optional[Union[str, Any, list[Any]]] = None,
|
| 104 |
+
**kwargs: Any,
|
| 105 |
+
) -> list[Any]:
|
| 106 |
+
if images is None and sar_images is None and optical_images is None:
|
| 107 |
+
raise ValueError("Provide at least one of `images`, `sar_images`, or `optical_images`.")
|
| 108 |
+
|
| 109 |
+
if images is None:
|
| 110 |
+
images = optical_images if optical_images is not None else sar_images
|
| 111 |
+
|
| 112 |
+
return Pipeline.__call__(self, images, sar_images=sar_images, optical_images=optical_images, **kwargs)
|
| 113 |
+
|
| 114 |
+
|
| 115 |
+
__all__ = ["CROMAImageFeatureExtractionPipeline"]
|
croma-large-patch8-120/preprocessor_config.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"image_processor_type": "CromaImageProcessor",
|
| 3 |
+
"size": {
|
| 4 |
+
"height": 120,
|
| 5 |
+
"width": 120
|
| 6 |
+
},
|
| 7 |
+
"do_resize": true,
|
| 8 |
+
"do_rescale": true,
|
| 9 |
+
"do_normalize": true,
|
| 10 |
+
"use_8_bit": true,
|
| 11 |
+
"do_convert_rgb": false,
|
| 12 |
+
"rescale_factor": 0.00392156862745098,
|
| 13 |
+
"auto_map": {
|
| 14 |
+
"AutoImageProcessor": "image_processing_croma.CromaImageProcessor"
|
| 15 |
+
}
|
| 16 |
+
}
|