Prompt48 commited on
Commit
8e28bfc
·
verified ·
1 Parent(s): 772ee85

Upload edit\Qwen3-TTS-test\.venv\Lib\site-packages\transformers\models\grounding_dino\processing_grounding_dino.py with huggingface_hub

Browse files
edit//Qwen3-TTS-test//.venv//Lib//site-packages//transformers//models//grounding_dino//processing_grounding_dino.py ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # coding=utf-8
2
+ # Copyright 2024 The HuggingFace Inc. team.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ """
16
+ Processor class for Grounding DINO.
17
+ """
18
+
19
+ import pathlib
20
+ import warnings
21
+ from typing import TYPE_CHECKING, Optional, Union
22
+
23
+ from ...image_transforms import center_to_corners_format
24
+ from ...image_utils import AnnotationFormat, ImageInput
25
+ from ...processing_utils import ImagesKwargs, ProcessingKwargs, ProcessorMixin, Unpack
26
+ from ...tokenization_utils_base import BatchEncoding, PreTokenizedInput, TextInput
27
+ from ...utils import TensorType, is_torch_available
28
+
29
+
30
+ if is_torch_available():
31
+ import torch
32
+
33
+ if TYPE_CHECKING:
34
+ from .modeling_grounding_dino import GroundingDinoObjectDetectionOutput
35
+
36
+
37
+ AnnotationType = dict[str, Union[int, str, list[dict]]]
38
+
39
+
40
+ def get_phrases_from_posmap(posmaps, input_ids):
41
+ """Get token ids of phrases from posmaps and input_ids.
42
+
43
+ Args:
44
+ posmaps (`torch.BoolTensor` of shape `(num_boxes, hidden_size)`):
45
+ A boolean tensor of text-thresholded logits related to the detected bounding boxes.
46
+ input_ids (`torch.LongTensor`) of shape `(sequence_length, )`):
47
+ A tensor of token ids.
48
+ """
49
+ left_idx = 0
50
+ right_idx = posmaps.shape[-1] - 1
51
+
52
+ # Avoiding altering the input tensor
53
+ posmaps = posmaps.clone()
54
+
55
+ posmaps[:, 0 : left_idx + 1] = False
56
+ posmaps[:, right_idx:] = False
57
+
58
+ token_ids = []
59
+ for posmap in posmaps:
60
+ non_zero_idx = posmap.nonzero(as_tuple=True)[0].tolist()
61
+ token_ids.append([input_ids[i] for i in non_zero_idx])
62
+
63
+ return token_ids
64
+
65
+
66
+ def _is_list_of_candidate_labels(text) -> bool:
67
+ """Check that text is list/tuple of strings and each string is a candidate label and not merged candidate labels text.
68
+ Merged candidate labels text is a string with candidate labels separated by a dot.
69
+ """
70
+ if isinstance(text, (list, tuple)):
71
+ return all(isinstance(t, str) and "." not in t for t in text)
72
+ return False
73
+
74
+
75
+ def _merge_candidate_labels_text(text: list[str]) -> str:
76
+ """
77
+ Merge candidate labels text into a single string. Ensure all labels are lowercase.
78
+ For example, ["A cat", "a dog"] -> "a cat. a dog."
79
+ """
80
+ labels = [t.strip().lower() for t in text] # ensure lowercase
81
+ merged_labels_str = ". ".join(labels) + "." # join with dot and add a dot at the end
82
+ return merged_labels_str
83
+
84
+
85
+ class DictWithDeprecationWarning(dict):
86
+ message = (
87
+ "The key `labels` is will return integer ids in `GroundingDinoProcessor.post_process_grounded_object_detection` "
88
+ "output since v4.51.0. Use `text_labels` instead to retrieve string object names."
89
+ )
90
+
91
+ def __getitem__(self, key):
92
+ if key == "labels":
93
+ warnings.warn(self.message, FutureWarning)
94
+ return super().__getitem__(key)
95
+
96
+ def get(self, key, *args, **kwargs):
97
+ if key == "labels":
98
+ warnings.warn(self.message, FutureWarning)
99
+ return super().get(key, *args, **kwargs)
100
+
101
+
102
+ class GroundingDinoImagesKwargs(ImagesKwargs, total=False):
103
+ annotations: Optional[Union[AnnotationType, list[AnnotationType]]]
104
+ return_segmentation_masks: Optional[bool]
105
+ masks_path: Optional[Union[str, pathlib.Path]]
106
+ do_convert_annotations: Optional[bool]
107
+ format: Optional[Union[str, AnnotationFormat]]
108
+
109
+
110
+ class GroundingDinoProcessorKwargs(ProcessingKwargs, total=False):
111
+ images_kwargs: GroundingDinoImagesKwargs
112
+ _defaults = {
113
+ "text_kwargs": {
114
+ "add_special_tokens": True,
115
+ "padding": False,
116
+ "stride": 0,
117
+ "return_overflowing_tokens": False,
118
+ "return_special_tokens_mask": False,
119
+ "return_offsets_mapping": False,
120
+ "return_token_type_ids": True,
121
+ "return_length": False,
122
+ "verbose": True,
123
+ }
124
+ }
125
+
126
+
127
+ class GroundingDinoProcessor(ProcessorMixin):
128
+ r"""
129
+ Constructs a Grounding DINO processor which wraps a Deformable DETR image processor and a BERT tokenizer into a
130
+ single processor.
131
+
132
+ [`GroundingDinoProcessor`] offers all the functionalities of [`GroundingDinoImageProcessor`] and
133
+ [`AutoTokenizer`]. See the docstring of [`~GroundingDinoProcessor.__call__`] and [`~GroundingDinoProcessor.decode`]
134
+ for more information.
135
+
136
+ Args:
137
+ image_processor (`GroundingDinoImageProcessor`):
138
+ An instance of [`GroundingDinoImageProcessor`]. The image processor is a required input.
139
+ tokenizer (`AutoTokenizer`):
140
+ An instance of ['PreTrainedTokenizer`]. The tokenizer is a required input.
141
+ """
142
+
143
+ attributes = ["image_processor", "tokenizer"]
144
+ image_processor_class = "GroundingDinoImageProcessor"
145
+ tokenizer_class = "AutoTokenizer"
146
+ valid_processor_kwargs = GroundingDinoProcessorKwargs
147
+
148
+ def __init__(self, image_processor, tokenizer):
149
+ super().__init__(image_processor, tokenizer)
150
+
151
+ def __call__(
152
+ self,
153
+ images: Optional[ImageInput] = None,
154
+ text: Union[TextInput, PreTokenizedInput, list[TextInput], list[PreTokenizedInput]] = None,
155
+ **kwargs: Unpack[GroundingDinoProcessorKwargs],
156
+ ) -> BatchEncoding:
157
+ """
158
+ This method uses [`GroundingDinoImageProcessor.__call__`] method to prepare image(s) for the model, and
159
+ [`BertTokenizerFast.__call__`] to prepare text for the model.
160
+
161
+ Args:
162
+ images (`ImageInput`, `list[ImageInput]`, *optional*):
163
+ The image or batch of images to be processed. The image might be either PIL image, numpy array or a torch tensor.
164
+ text (`TextInput`, `PreTokenizedInput`, `list[TextInput]`, `list[PreTokenizedInput]`, *optional*):
165
+ Candidate labels to be detected on the image. The text might be one of the following:
166
+ - A list of candidate labels (strings) to be detected on the image (e.g. ["a cat", "a dog"]).
167
+ - A batch of candidate labels to be detected on the batch of images (e.g. [["a cat", "a dog"], ["a car", "a person"]]).
168
+ - A merged candidate labels string to be detected on the image, separated by "." (e.g. "a cat. a dog.").
169
+ - A batch of merged candidate labels text to be detected on the batch of images (e.g. ["a cat. a dog.", "a car. a person."]).
170
+ """
171
+ if text is not None:
172
+ text = self._preprocess_input_text(text)
173
+ return super().__call__(images=images, text=text, **kwargs)
174
+
175
+ def _preprocess_input_text(self, text):
176
+ """
177
+ Preprocess input text to ensure that labels are in the correct format for the model.
178
+ If the text is a list of candidate labels, merge the candidate labels into a single string,
179
+ for example, ["a cat", "a dog"] -> "a cat. a dog.". In case candidate labels are already in a form of
180
+ "a cat. a dog.", the text is returned as is.
181
+ """
182
+
183
+ if _is_list_of_candidate_labels(text):
184
+ text = _merge_candidate_labels_text(text)
185
+
186
+ # for batched input
187
+ elif isinstance(text, (list, tuple)) and all(_is_list_of_candidate_labels(t) for t in text):
188
+ text = [_merge_candidate_labels_text(sample) for sample in text]
189
+
190
+ return text
191
+
192
+ def post_process_grounded_object_detection(
193
+ self,
194
+ outputs: "GroundingDinoObjectDetectionOutput",
195
+ input_ids: Optional[TensorType] = None,
196
+ threshold: float = 0.25,
197
+ text_threshold: float = 0.25,
198
+ target_sizes: Optional[Union[TensorType, list[tuple]]] = None,
199
+ text_labels: Optional[list[list[str]]] = None,
200
+ ):
201
+ """
202
+ Converts the raw output of [`GroundingDinoForObjectDetection`] into final bounding boxes in (top_left_x, top_left_y,
203
+ bottom_right_x, bottom_right_y) format and get the associated text label.
204
+
205
+ Args:
206
+ outputs ([`GroundingDinoObjectDetectionOutput`]):
207
+ Raw outputs of the model.
208
+ input_ids (`torch.LongTensor` of shape `(batch_size, sequence_length)`, *optional*):
209
+ The token ids of the input text. If not provided will be taken from the model output.
210
+ threshold (`float`, *optional*, defaults to 0.25):
211
+ Threshold to keep object detection predictions based on confidence score.
212
+ text_threshold (`float`, *optional*, defaults to 0.25):
213
+ Score threshold to keep text detection predictions.
214
+ target_sizes (`torch.Tensor` or `list[tuple[int, int]]`, *optional*):
215
+ Tensor of shape `(batch_size, 2)` or list of tuples (`tuple[int, int]`) containing the target size
216
+ `(height, width)` of each image in the batch. If unset, predictions will not be resized.
217
+ text_labels (`list[list[str]]`, *optional*):
218
+ List of candidate labels to be detected on each image. At the moment it's *NOT used*, but required
219
+ to be in signature for the zero-shot object detection pipeline. Text labels are instead extracted
220
+ from the `input_ids` tensor provided in `outputs`.
221
+
222
+ Returns:
223
+ `list[Dict]`: A list of dictionaries, each dictionary containing the
224
+ - **scores**: tensor of confidence scores for detected objects
225
+ - **boxes**: tensor of bounding boxes in [x0, y0, x1, y1] format
226
+ - **labels**: list of text labels for each detected object (will be replaced with integer ids in v4.51.0)
227
+ - **text_labels**: list of text labels for detected objects
228
+ """
229
+ batch_logits, batch_boxes = outputs.logits, outputs.pred_boxes
230
+ input_ids = input_ids if input_ids is not None else outputs.input_ids
231
+
232
+ if target_sizes is not None and len(target_sizes) != len(batch_logits):
233
+ raise ValueError("Make sure that you pass in as many target sizes as the batch dimension of the logits")
234
+
235
+ batch_probs = torch.sigmoid(batch_logits) # (batch_size, num_queries, 256)
236
+ batch_scores = torch.max(batch_probs, dim=-1)[0] # (batch_size, num_queries)
237
+
238
+ # Convert to [x0, y0, x1, y1] format
239
+ batch_boxes = center_to_corners_format(batch_boxes)
240
+
241
+ # Convert from relative [0, 1] to absolute [0, height] coordinates
242
+ if target_sizes is not None:
243
+ if isinstance(target_sizes, list):
244
+ img_h = torch.Tensor([i[0] for i in target_sizes])
245
+ img_w = torch.Tensor([i[1] for i in target_sizes])
246
+ else:
247
+ img_h, img_w = target_sizes.unbind(1)
248
+
249
+ scale_fct = torch.stack([img_w, img_h, img_w, img_h], dim=1).to(batch_boxes.device)
250
+ batch_boxes = batch_boxes * scale_fct[:, None, :]
251
+
252
+ results = []
253
+ for idx, (scores, boxes, probs) in enumerate(zip(batch_scores, batch_boxes, batch_probs)):
254
+ keep = scores > threshold
255
+ scores = scores[keep]
256
+ boxes = boxes[keep]
257
+
258
+ # extract text labels
259
+ prob = probs[keep]
260
+ label_ids = get_phrases_from_posmap(prob > text_threshold, input_ids[idx])
261
+ objects_text_labels = self.batch_decode(label_ids)
262
+
263
+ result = DictWithDeprecationWarning(
264
+ {
265
+ "scores": scores,
266
+ "boxes": boxes,
267
+ "text_labels": objects_text_labels,
268
+ # TODO: @pavel, set labels to None since v4.51.0 or find a way to extract ids
269
+ "labels": objects_text_labels,
270
+ }
271
+ )
272
+ results.append(result)
273
+
274
+ return results
275
+
276
+
277
+ __all__ = ["GroundingDinoProcessor"]