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"]
|