Aluode/PerceptionLabPortable
0
1# coding=utf-82# Copyright 2025 Google Inc. HuggingFace Inc. team. All rights reserved.3#4#5# Licensed under the Apache License, Version 2.0 (the "License");6# you may not use this file except in compliance with the License.7# You may obtain a copy of the License at8#9# http://www.apache.org/licenses/LICENSE-2.010#11# Unless required by applicable law or agreed to in writing, software12# distributed under the License is distributed on an "AS IS" BASIS,13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.14# See the License for the specific language governing permissions and15# limitations under the License.16from typing import Optional, Union17 18import numpy as np19 20from ...feature_extraction_utils import BatchFeature21from ...image_utils import ImageInput, make_nested_list_of_images22from ...processing_utils import AudioKwargs, ImagesKwargs, ProcessingKwargs, ProcessorMixin, Unpack23from ...tokenization_utils_base import PreTokenizedInput, TextInput24 25 26class Gemma3nImagesKwargs(ImagesKwargs):27 do_convert_rgb: Optional[bool]28 29 30class Gemma3nProcessorKwargs(ProcessingKwargs, total=False):31 audio_kwargs: AudioKwargs32 images_kwargs: Gemma3nImagesKwargs33 _defaults = {34 "text_kwargs": {35 "padding": False,36 },37 }38 39 40class Gemma3nProcessor(ProcessorMixin):41 """42 A processor for Gemma 3n, wrapping the full capabilities of a feature extractor, image processor, and tokenizer43 into a single processor.44 45 Args:46 feature_extractor (`Gemma3nAudioFeatureExtractor`):47 Feature extractor that converts raw audio waveforms into MEL spectrograms for the audio encoder. This48 should return a `BatchFeature` with `input_features` and `input_features_mask` features.49 image_processor (`SiglipImageProcessorFast`):50 Image processor that prepares batches of images for the vision encoder. This should return a `BatchFeature`51 with a `pixel_values` feature.52 tokenizer (`GemmaTokenizerFast`):53 The text tokenizer for the model.54 chat_template (`string`, *optional*):55 A Jinja template for generating text prompts from a set of messages.56 audio_seq_length (int, *optional*, defaults to 188):57 The number of audio soft tokens that will be added to the text prompt58 image_seq_length (int, *optional*, defaults to 256):59 The number of image soft tokens that should be added to60 """61 62 attributes = ["feature_extractor", "image_processor", "tokenizer"]63 feature_extractor_class = "AutoFeatureExtractor"64 image_processor_class = "AutoImageProcessor"65 tokenizer_class = "AutoTokenizer"66 67 def __init__(68 self,69 feature_extractor,70 image_processor,71 tokenizer,72 chat_template=None,73 audio_seq_length: int = 188,74 image_seq_length: int = 256,75 **kwargs,76 ):77 self.audio_seq_length = audio_seq_length78 self.audio_token_id = tokenizer.audio_token_id79 self.boa_token = tokenizer.boa_token80 self.audio_token = tokenizer.audio_token81 audio_tokens_expanded = "".join([tokenizer.audio_token] * audio_seq_length)82 self.full_audio_sequence = f"\n\n{tokenizer.boa_token}{audio_tokens_expanded}{tokenizer.eoa_token}\n\n"83 84 self.image_seq_length = image_seq_length85 self.image_token_id = tokenizer.image_token_id86 self.boi_token = tokenizer.boi_token87 self.image_token = tokenizer.image_token88 image_tokens_expanded = "".join([tokenizer.image_token] * image_seq_length)89 self.full_image_sequence = f"\n\n{tokenizer.boi_token}{image_tokens_expanded}{tokenizer.eoi_token}\n\n"90 91 super().__init__(92 feature_extractor=feature_extractor,93 image_processor=image_processor,94 tokenizer=tokenizer,95 chat_template=chat_template,96 **kwargs,97 )98 99 def __call__(100 self,101 images: Optional[ImageInput] = None,102 text: Union[TextInput, PreTokenizedInput, list[TextInput], list[PreTokenizedInput]] = None,103 audio: Optional[Union[np.ndarray, list[float], list[np.ndarray], list[list[float]]]] = None,104 videos=None,105 **kwargs: Unpack[Gemma3nProcessorKwargs],106 ) -> BatchFeature:107 if text is None and images is None and audio is None:108 raise ValueError("Provide at least one of `text`, `images`, or `audio`.")109 110 output_kwargs = self._merge_kwargs(111 Gemma3nProcessorKwargs,112 tokenizer_init_kwargs=self.tokenizer.init_kwargs,113 **kwargs,114 )115 116 if isinstance(text, str):117 text = [text]118 elif not isinstance(text, list) and not isinstance(text[0], str):119 raise ValueError("Invalid input text. Please provide a string, or a list of strings")120 121 if audio is not None:122 audio_inputs = self.feature_extractor(audio, **output_kwargs["audio_kwargs"])123 124 if not text:125 text = [self.audio_token for _ in audio]126 127 # Expand placeholder audio tokens to the full audio token sequence128 text = [prompt.replace(self.audio_token, self.full_audio_sequence) for prompt in text]129 else:130 audio_inputs = {}131 132 if images is not None:133 images = self.image_processor.fetch_images(images)134 batched_images = make_nested_list_of_images(images)135 image_inputs = self.image_processor(batched_images, **output_kwargs["images_kwargs"])136 137 # Create empty text to be replaced with placeholders138 if not text:139 text = [" ".join([self.image_token] * len(images)) for images in batched_images]140 141 if len(batched_images) != len(text):142 raise ValueError(143 f"Received inconsistently sized batches of images ({len(batched_images)}) and text ({len(text)})."144 )145 146 # Expand placeholder image tokens to the full image token sequence147 text = [prompt.replace(self.image_token, self.full_image_sequence) for prompt in text]148 else:149 image_inputs = {}150 151 return_tensors = output_kwargs["text_kwargs"].pop("return_tensors", None)152 text_inputs = self.tokenizer(text=text, **output_kwargs["text_kwargs"], return_tensors="np")153 self._check_special_mm_tokens(text, text_inputs, modalities=["image"])154 155 # Add token type ids manually, as tokenizer can't do arbitrary position token types156 array_ids = text_inputs["input_ids"]157 token_type_ids = np.zeros_like(array_ids)158 token_type_ids[array_ids == self.image_token_id] = 1159 token_type_ids[array_ids == self.audio_token_id] = 3160 text_inputs = {k: v.tolist() for k, v in text_inputs.items()} # in case user requested list inputs161 text_inputs["token_type_ids"] = token_type_ids.tolist()162 return BatchFeature(data={**text_inputs, **image_inputs, **audio_inputs}, tensor_type=return_tensors)163 164 165__all__ = ["Gemma3nProcessor"]166 