Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
204d643
adding fast processor for beit
ariG23498 Mar 26, 2025
d266e74
adding resample
ariG23498 Mar 26, 2025
8d7655b
Merge branch 'main' into aritra/fp-beit
ariG23498 Mar 26, 2025
9510e0f
address review issues and add segmentation maps logic
ariG23498 Mar 27, 2025
f893167
Merge branch 'main' into aritra/fp-beit
ariG23498 Mar 27, 2025
a09b91c
style
ariG23498 Mar 27, 2025
85ced8f
chore: adding tests
ariG23498 Mar 27, 2025
bb81748
reduce label test
ariG23498 Mar 27, 2025
d8c4e13
adding batched tests
ariG23498 Mar 27, 2025
77e3fcf
Update src/transformers/models/beit/image_processing_beit_fast.py
ariG23498 Apr 8, 2025
4931ad7
fix imports and make segmentation masks
ariG23498 Apr 8, 2025
da3fbfa
Merge branch 'main' into aritra/fp-beit
ariG23498 Apr 8, 2025
6877afa
fix tests
ariG23498 Apr 8, 2025
ce7e704
build segmentation maps
ariG23498 Apr 8, 2025
647090c
resolve conflicts
ariG23498 Apr 15, 2025
0bd8b2d
all tests pass
ariG23498 Apr 15, 2025
3383d8c
style
ariG23498 Apr 15, 2025
49cc6bd
style fix
ariG23498 Apr 15, 2025
35e5c94
resolve conflicts
ariG23498 Apr 17, 2025
0a5e38c
style
ariG23498 Apr 17, 2025
094308a
Merge branch 'main' into aritra/fp-beit
ariG23498 Apr 22, 2025
72486fb
Merge branch 'main' into aritra/fp-beit
ariG23498 Apr 29, 2025
37e3827
chore: delete demo.py file
ariG23498 Apr 29, 2025
4f5f002
review suggestions
ariG23498 Apr 29, 2025
bb71922
Update docs/source/en/model_doc/beit.md
ariG23498 May 6, 2025
e5b5cf7
Merge branch 'main' into aritra/fp-beit
ariG23498 May 6, 2025
f63b71f
Merge branch 'main' into aritra/fp-beit
yonigozlan May 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/source/en/model_doc/beit.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ If you're interested in submitting a resource to be included here, please feel f
[[autodoc]] BeitImageProcessor
- preprocess
- post_process_semantic_segmentation
## BeitImageProcessorFast

[[autodoc]] BeitImageProcessorFast
- preprocess
- post_process_semantic_segmentation

<frameworkcontent>
<pt>
Expand Down
5 changes: 5 additions & 0 deletions docs/source/ja/model_doc/beit.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@ BEiT の使用を開始するのに役立つ公式 Hugging Face およびコミ

[[autodoc]] BeitImageProcessor
- preprocess

## BeitImageProcessorFast

[[autodoc]] BeitImageProcessorFast
- preprocess
- post_process_semantic_segmentation

## BeitModel
Expand Down
6 changes: 3 additions & 3 deletions src/transformers/models/auto/image_processing_auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
IMAGE_PROCESSOR_MAPPING_NAMES = OrderedDict(
[
("align", ("EfficientNetImageProcessor", "EfficientNetImageProcessorFast")),
("aria", ("AriaImageProcessor",)),
("beit", ("BeitImageProcessor",)),
("aria", ("AriaImageProcessor")),
("beit", ("BeitImageProcessor", "BeitImageProcessorFast")),
("bit", ("BitImageProcessor", "BitImageProcessorFast")),
("blip", ("BlipImageProcessor", "BlipImageProcessorFast")),
("blip-2", ("BlipImageProcessor", "BlipImageProcessorFast")),
Expand All @@ -71,7 +71,7 @@
("convnext", ("ConvNextImageProcessor", "ConvNextImageProcessorFast")),
("convnextv2", ("ConvNextImageProcessor", "ConvNextImageProcessorFast")),
("cvt", ("ConvNextImageProcessor", "ConvNextImageProcessorFast")),
("data2vec-vision", ("BeitImageProcessor",)),
("data2vec-vision", ("BeitImageProcessor", "BeitImageProcessorFast")),
("deformable_detr", ("DeformableDetrImageProcessor", "DeformableDetrImageProcessorFast")),
("deit", ("DeiTImageProcessor", "DeiTImageProcessorFast")),
("depth_anything", ("DPTImageProcessor",)),
Expand Down
1 change: 1 addition & 0 deletions src/transformers/models/beit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from .configuration_beit import *
from .feature_extraction_beit import *
from .image_processing_beit import *
from .image_processing_beit_fast import *
from .modeling_beit import *
from .modeling_flax_beit import *
else:
Expand Down
284 changes: 284 additions & 0 deletions src/transformers/models/beit/image_processing_beit_fast.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,284 @@
# coding=utf-8
# Copyright 2025 The HuggingFace Inc. team. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Fast Image processor class for Beit."""

from typing import Any, Dict, List, Optional, Tuple, Union

import torch
from torchvision.transforms import functional as F

from ...image_processing_utils import BatchFeature
from ...image_processing_utils_fast import (
BASE_IMAGE_PROCESSOR_FAST_DOCSTRING,
BaseImageProcessorFast,
DefaultFastImageProcessorKwargs,
group_images_by_shape,
reorder_images,
)
from ...image_utils import (
IMAGENET_STANDARD_MEAN,
IMAGENET_STANDARD_STD,
ChannelDimension,
ImageInput,
PILImageResampling,
SizeDict,
is_torch_tensor,
make_list_of_images,
pil_torch_interpolation_mapping,
validate_kwargs,
)
from ...processing_utils import Unpack
from ...utils import TensorType, add_start_docstrings
from ...utils.deprecation import deprecate_kwarg


class BeitFastImageProcessorKwargs(DefaultFastImageProcessorKwargs):
do_reduce_labels: Optional[bool]


@add_start_docstrings(
"Constructs a fast Beit image processor.",
BASE_IMAGE_PROCESSOR_FAST_DOCSTRING,
"""
do_reduce_labels (`bool`, *optional*, defaults to `self.do_reduce_labels`):
Whether or not to reduce all label values of segmentation maps by 1. Usually used for datasets where 0
is used for background, and background itself is not included in all classes of a dataset (e.g.
ADE20k). The background label will be replaced by 255.
""",
)
class BeitImageProcessorFast(BaseImageProcessorFast):
resample = PILImageResampling.BICUBIC
image_mean = IMAGENET_STANDARD_MEAN
image_std = IMAGENET_STANDARD_STD
size = {"height": 224, "width": 224}
default_to_square = True
crop_size = {"height": 224, "width": 224}
do_resize = True
do_center_crop = False
do_rescale = True
do_normalize = True
do_reduce_labels = False
Comment thread
ariG23498 marked this conversation as resolved.
valid_kwargs = BeitFastImageProcessorKwargs

@classmethod
def from_dict(cls, image_processor_dict: Dict[str, Any], **kwargs):
"""
Overrides the `from_dict` method from the base class to save support of deprecated `reduce_labels` in old configs
"""
image_processor_dict = image_processor_dict.copy()
if "reduce_labels" in image_processor_dict:
image_processor_dict["do_reduce_labels"] = image_processor_dict.pop("reduce_labels")
return super().from_dict(image_processor_dict, **kwargs)

def reduce_label(self, labels: list["torch.Tensor"]):
for idx in range(len(labels)):
label = labels[idx]
label = torch.where(label == 0, torch.tensor(255, dtype=label.dtype), label)
label = label - 1
label = torch.where(label == 254, torch.tensor(255, dtype=label.dtype), label)
labels[idx] = label

return label

def _preprocess(
self,
images: list["torch.Tensor"],
do_reduce_labels: bool,
do_resize: bool,
size: SizeDict,
interpolation: Optional["F.InterpolationMode"],
do_center_crop: bool,
crop_size: SizeDict,
do_rescale: bool,
rescale_factor: float,
do_normalize: bool,
image_mean: Optional[Union[float, list[float]]],
image_std: Optional[Union[float, list[float]]],
return_tensors: Optional[Union[str, TensorType]],
**kwargs,
) -> BatchFeature:
if do_reduce_labels:
images = self.reduce_label(images)

# Group images by size for batched resizing
grouped_images, grouped_images_index = group_images_by_shape(images)
resized_images_grouped = {}
for shape, stacked_images in grouped_images.items():
if do_resize:
stacked_images = self.resize(image=stacked_images, size=size, interpolation=interpolation)
resized_images_grouped[shape] = stacked_images
resized_images = reorder_images(resized_images_grouped, grouped_images_index)

# Group images by size for further processing
# Needed in case do_resize is False, or resize returns images with different sizes
grouped_images, grouped_images_index = group_images_by_shape(resized_images)
processed_images_grouped = {}
for shape, stacked_images in grouped_images.items():
if do_center_crop:
stacked_images = self.center_crop(stacked_images, crop_size)
# Fused rescale and normalize
stacked_images = self.rescale_and_normalize(
stacked_images, do_rescale, rescale_factor, do_normalize, image_mean, image_std
)
processed_images_grouped[shape] = stacked_images

processed_images = reorder_images(processed_images_grouped, grouped_images_index)
processed_images = torch.stack(processed_images, dim=0) if return_tensors else processed_images
return processed_images

def _preprocess_segmentation_maps(
self,
segmentation_maps,
**kwargs,
):
"""Preprocesses a single segmentation map."""
processed_segmentation_maps = []
for segmentation_map in segmentation_maps:
segmentation_map = self._process_image(
segmentation_map, do_convert_rgb=False, input_data_format=ChannelDimension.FIRST
)

if segmentation_map.ndim == 2:
segmentation_map = segmentation_map[None, ...]

processed_segmentation_maps.append(segmentation_map)

kwargs["do_normalize"] = False
kwargs["do_rescale"] = False
kwargs["input_data_format"] = ChannelDimension.FIRST
processed_segmentation_maps = self._preprocess(images=processed_segmentation_maps, **kwargs)

processed_segmentation_maps = processed_segmentation_maps.squeeze(1)

processed_segmentation_maps = processed_segmentation_maps.to(torch.int64)
return processed_segmentation_maps

def __call__(self, images, segmentation_maps=None, **kwargs):
# Overrides the `__call__` method of the `Preprocessor` class such that the images and segmentation maps can both
# be passed in as positional arguments.
return super().__call__(images, segmentation_maps=segmentation_maps, **kwargs)

@deprecate_kwarg("reduce_labels", new_name="do_reduce_labels", version="4.41.0")
@add_start_docstrings(
"Constructs a fast Beit image processor.",
BASE_IMAGE_PROCESSOR_FAST_DOCSTRING,
"""
do_reduce_labels (`bool`, *optional*, defaults to `self.do_reduce_labels`):
Whether or not to reduce all label values of segmentation maps by 1. Usually used for datasets where 0
is used for background, and background itself is not included in all classes of a dataset (e.g.
ADE20k). The background label will be replaced by 255.
""",
)
def preprocess(
self,
images: ImageInput,
segmentation_maps: Optional[ImageInput] = None,
**kwargs: Unpack[DefaultFastImageProcessorKwargs],
) -> BatchFeature:
validate_kwargs(captured_kwargs=kwargs.keys(), valid_processor_keys=self.valid_kwargs.__annotations__.keys())
# Set default kwargs from self. This ensures that if a kwarg is not provided
# by the user, it gets its default value from the instance, or is set to None.
for kwarg_name in self.valid_kwargs.__annotations__:
kwargs.setdefault(kwarg_name, getattr(self, kwarg_name, None))

# Extract parameters that are only used for preparing the input images
do_convert_rgb = kwargs.pop("do_convert_rgb")
input_data_format = kwargs.pop("input_data_format")
device = kwargs.pop("device")
# Prepare input images
images = self._prepare_input_images(
images=images, do_convert_rgb=do_convert_rgb, input_data_format=input_data_format, device=device
)

# Prepare segmentation maps
if segmentation_maps is not None:
segmentation_maps = make_list_of_images(images=segmentation_maps, expected_ndims=2)
Comment on lines +206 to +207

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes my bad sorry, we do need to convert the segmentation maps to tensors before doing this, and also we should handle the added_dimension logic as in the slow processor

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think the best way would be to use self._prepare_input_images instead of make_list_of_images?


# Update kwargs that need further processing before being validated
kwargs = self._further_process_kwargs(**kwargs)

# Validate kwargs
self._validate_preprocess_kwargs(**kwargs)

# torch resize uses interpolation instead of resample
resample = kwargs.pop("resample")
kwargs["interpolation"] = (
pil_torch_interpolation_mapping[resample] if isinstance(resample, (PILImageResampling, int)) else resample
)

# Pop kwargs that are not needed in _preprocess
kwargs.pop("default_to_square")
kwargs.pop("data_format")

images = self._preprocess(
images=images,
**kwargs,
)
data = {"pixel_values": images}

if segmentation_maps is not None:
segmentation_maps = self._preprocess_segmentation_maps(
segmentation_maps=segmentation_maps,
**kwargs,
)
data["labels"] = segmentation_maps

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we will need to squeeze or not the channel dimension depending on added_dimension


return BatchFeature(data=data)

def post_process_semantic_segmentation(self, outputs, target_sizes: List[Tuple] = None):
"""
Converts the output of [`BeitForSemanticSegmentation`] into semantic segmentation maps. Only supports PyTorch.

Args:
outputs ([`BeitForSemanticSegmentation`]):
Raw outputs of the model.
target_sizes (`List[Tuple]` of length `batch_size`, *optional*):
List of tuples corresponding to the requested final size (height, width) of each prediction. If unset,
predictions will not be resized.

Returns:
semantic_segmentation: `List[torch.Tensor]` of length `batch_size`, where each item is a semantic
segmentation map of shape (height, width) corresponding to the target_sizes entry (if `target_sizes` is
specified). Each entry of each `torch.Tensor` correspond to a semantic class id.
"""
# TODO: add support for other frameworks
logits = outputs.logits

# Resize logits and compute semantic segmentation maps
if target_sizes is not None:
if len(logits) != len(target_sizes):
raise ValueError(
"Make sure that you pass in as many target sizes as the batch dimension of the logits"
)

if is_torch_tensor(target_sizes):
target_sizes = target_sizes.numpy()

semantic_segmentation = []

for idx in range(len(logits)):
resized_logits = torch.nn.functional.interpolate(
logits[idx].unsqueeze(dim=0), size=target_sizes[idx], mode="bilinear", align_corners=False
)
semantic_map = resized_logits[0].argmax(dim=0)
semantic_segmentation.append(semantic_map)
else:
semantic_segmentation = logits.argmax(dim=1)
semantic_segmentation = [semantic_segmentation[i] for i in range(semantic_segmentation.shape[0])]

return semantic_segmentation

Comment thread
ariG23498 marked this conversation as resolved.

__all__ = ["BeitImageProcessorFast"]
Loading