BiliSakura commited on
Commit
930dfab
·
verified ·
1 Parent(s): 7695c0f

Upload CROMA transformers checkpoints with model card metadata

Browse files
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
+ }