CCCCyx commited on
Commit
39e7138
·
verified ·
1 Parent(s): 25a35b2

Update processing_moss_vl.py

Browse files
Files changed (1) hide show
  1. processing_moss_vl.py +77 -22
processing_moss_vl.py CHANGED
@@ -23,8 +23,8 @@ import torch
23
  from torchvision.transforms.v2 import functional as F
24
  from PIL import Image
25
  from transformers.feature_extraction_utils import BatchFeature
26
- from transformers.image_utils import ImageInput, SizeDict
27
- from transformers.image_processing_utils_fast import group_images_by_shape, reorder_images
28
  from transformers.utils import TensorType
29
  from transformers.processing_utils import (
30
  ImagesKwargs,
@@ -35,17 +35,16 @@ from transformers.processing_utils import (
35
  )
36
  from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
37
  from transformers.utils import logging
38
- from transformers.models.qwen2_vl.image_processing_qwen2_vl_fast import Qwen2VLImageProcessorFast
39
- from transformers.models.qwen2_vl.image_processing_qwen2_vl import smart_resize
40
 
41
 
42
  logger = logging.get_logger(__name__)
43
 
44
 
45
- class MossVLImageProcessorFast(Qwen2VLImageProcessorFast):
46
  """
47
  Custom image processor that overrides _preprocess to support multi_image_max_pixels.
48
- Inherits from Qwen2VLImageProcessorFast.
49
  """
50
  # Multi-image batch total pixels limit (read from config)
51
  multi_image_max_pixels = None
@@ -56,7 +55,7 @@ class MossVLImageProcessorFast(Qwen2VLImageProcessorFast):
56
  images: list["torch.Tensor"],
57
  do_resize: bool,
58
  size: SizeDict,
59
- resample: Optional["F.InterpolationMode"],
60
  do_rescale: bool,
61
  rescale_factor: float,
62
  do_normalize: bool,
@@ -75,6 +74,8 @@ class MossVLImageProcessorFast(Qwen2VLImageProcessorFast):
75
  to each image based on its original pixel count. min_pixels remains a per-image
76
  constraint. multi_image_max_pixels can be configured separately from longest_edge.
77
  """
 
 
78
  min_pixels = size["shortest_edge"]
79
  max_pixels = size["longest_edge"] # Per-image upper limit
80
  # Use multi_image_max_pixels if configured, otherwise fall back to longest_edge
@@ -214,6 +215,58 @@ def _to_numpy(x):
214
  return np.array(x)
215
 
216
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  class MossVLImagesKwargs(ImagesKwargs):
218
  min_pixels: Optional[int]
219
  max_pixels: Optional[int]
@@ -256,10 +309,8 @@ class MossVLProcessor(ProcessorMixin):
256
  r"""
257
  Constructs a Moss-VL processor which wraps a Qwen2VL image processor, Moss-VL video processor and a Qwen2 tokenizer
258
  into a single processor.
259
-
260
  [`MossVLProcessor`] offers all the functionalities of [`Qwen2VLImageProcessor`], [`MossVLVideoProcessor`] and [`Qwen2TokenizerFast`].
261
  See the [`~MossVLProcessor.__call__`] and [`~MossVLProcessor.decode`] for more information.
262
-
263
  Args:
264
  image_processor ([`Qwen2VLImageProcessor`], *optional*):
265
  The image processor is a required input.
@@ -272,8 +323,6 @@ class MossVLProcessor(ProcessorMixin):
272
  """
273
 
274
  attributes = ["image_processor", "tokenizer", "video_processor"]
275
- image_processor_class = "AutoImageProcessor"
276
- video_processor_class = "AutoVideoProcessor"
277
  tokenizer_class = ("Qwen2Tokenizer", "Qwen2TokenizerFast")
278
 
279
  def __init__(
@@ -338,7 +387,6 @@ class MossVLProcessor(ProcessorMixin):
338
  ) -> BatchFeature:
339
  """
340
  Main method to prepare for the model one or several sequences(s) and image(s)/video(s).
341
-
342
  Args:
343
  text (`str`, `list[str]`, `list[list[str]]`):
344
  The sequence or batch of sequences to be encoded.
@@ -370,8 +418,6 @@ class MossVLProcessor(ProcessorMixin):
370
  - `'pt'`: Return PyTorch `torch.Tensor` objects.
371
  - `'np'`: Return NumPy `np.ndarray` objects.
372
  - `'jax'`: Return JAX `jnp.ndarray` objects.
373
-
374
-
375
  Returns:
376
  [`BatchFeature`]: A [`BatchFeature`] with the following fields:
377
  - **input_ids** -- List of token ids to be fed to a model.
@@ -485,7 +531,9 @@ class MossVLProcessor(ProcessorMixin):
485
  elif len(patch_counts) > 1:
486
  # Multiple images: split by cumulative counts
487
  split_indices = np.cumsum(patch_counts)[:-1]
488
- image_pixel_values_list = np.split(flat_pixel_values, split_indices)
 
 
489
 
490
  if has_videos:
491
  flat_video_values = videos_inputs["pixel_values_videos"]
@@ -497,7 +545,9 @@ class MossVLProcessor(ProcessorMixin):
497
  elif len(video_patch_counts) > 1:
498
  # Multiple videos: split by cumulative counts
499
  split_indices = np.cumsum(video_patch_counts)[:-1]
500
- video_pixel_values_list = np.split(flat_video_values, split_indices)
 
 
501
 
502
  # Step 3.1: Replace placeholders (simple replacement, no expansion yet)
503
  # In MossVL, one image placeholder = one image token
@@ -713,10 +763,14 @@ class MossVLProcessor(ProcessorMixin):
713
 
714
  # Concatenate/stack to unified format
715
  if final_pixel_values:
716
- output_data["pixel_values"] = np.concatenate(final_pixel_values, axis=0)
 
 
717
 
718
  if final_grid_thw:
719
- output_data["grid_thw"] = np.stack(final_grid_thw, axis=0)
 
 
720
 
721
  # Don't add media_nums_per_sample to output_data yet
722
  # Will add it after BatchFeature to keep it as list
@@ -773,6 +827,10 @@ class MossVLProcessor(ProcessorMixin):
773
  for _ in range(num_media):
774
  # grid_thw is (N, 3) where first dim is t (num_frames)
775
  t = grid_thw[media_idx][0]
 
 
 
 
776
  sample_frames += t
777
  media_idx += 1
778
  total_frames_per_sample.append(sample_frames)
@@ -1053,7 +1111,6 @@ class MossVLProcessor(ProcessorMixin):
1053
  ):
1054
  """
1055
  Post-process the output of the model to decode the text.
1056
-
1057
  Args:
1058
  generated_outputs (`torch.Tensor` or `np.ndarray`):
1059
  The output of the model `generate` function. The output is expected to be a tensor
@@ -1064,7 +1121,6 @@ class MossVLProcessor(ProcessorMixin):
1064
  Whether or not to clean up the tokenization spaces.
1065
  **kwargs:
1066
  Additional arguments to be passed to the tokenizer's `batch_decode` method.
1067
-
1068
  Returns:
1069
  `list[str]`: The decoded text.
1070
  """
@@ -1075,5 +1131,4 @@ class MossVLProcessor(ProcessorMixin):
1075
  **kwargs,
1076
  )
1077
 
1078
-
1079
- __all__ = ["MossVLProcessor", "MossVLImageProcessorFast"]
 
23
  from torchvision.transforms.v2 import functional as F
24
  from PIL import Image
25
  from transformers.feature_extraction_utils import BatchFeature
26
+ from transformers.image_utils import ImageInput, PILImageResampling, SizeDict
27
+ from transformers.image_transforms import group_images_by_shape, reorder_images
28
  from transformers.utils import TensorType
29
  from transformers.processing_utils import (
30
  ImagesKwargs,
 
35
  )
36
  from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
37
  from transformers.utils import logging
38
+ from transformers.models.qwen2_vl.image_processing_qwen2_vl import Qwen2VLImageProcessor, smart_resize
 
39
 
40
 
41
  logger = logging.get_logger(__name__)
42
 
43
 
44
+ class MossVLImageProcessor(Qwen2VLImageProcessor):
45
  """
46
  Custom image processor that overrides _preprocess to support multi_image_max_pixels.
47
+ Inherits from Qwen2VLImageProcessor.
48
  """
49
  # Multi-image batch total pixels limit (read from config)
50
  multi_image_max_pixels = None
 
55
  images: list["torch.Tensor"],
56
  do_resize: bool,
57
  size: SizeDict,
58
+ resample: Optional[Union["PILImageResampling", "F.InterpolationMode", int]],
59
  do_rescale: bool,
60
  rescale_factor: float,
61
  do_normalize: bool,
 
74
  to each image based on its original pixel count. min_pixels remains a per-image
75
  constraint. multi_image_max_pixels can be configured separately from longest_edge.
76
  """
77
+ if resample is None:
78
+ resample = kwargs.pop("interpolation", None)
79
  min_pixels = size["shortest_edge"]
80
  max_pixels = size["longest_edge"] # Per-image upper limit
81
  # Use multi_image_max_pixels if configured, otherwise fall back to longest_edge
 
215
  return np.array(x)
216
 
217
 
218
+ def _split_array_or_tensor(x, split_indices):
219
+ """Split along the first dimension while preserving tensor/array type."""
220
+ split_indices = [int(idx) for idx in split_indices]
221
+ if isinstance(x, torch.Tensor):
222
+ if not split_indices:
223
+ return [x]
224
+ chunks = []
225
+ start = 0
226
+ for end in split_indices:
227
+ chunks.append(x[start:end])
228
+ start = end
229
+ chunks.append(x[start:])
230
+ return chunks
231
+ return np.split(x, split_indices)
232
+
233
+
234
+ def _concat_array_or_tensor(items, axis=0):
235
+ """Concatenate while preserving tensor/array type and device."""
236
+ if not items:
237
+ return None
238
+
239
+ if any(isinstance(item, torch.Tensor) for item in items):
240
+ ref = next(item for item in items if isinstance(item, torch.Tensor))
241
+ tensor_items = [
242
+ item
243
+ if isinstance(item, torch.Tensor)
244
+ else torch.as_tensor(item, device=ref.device, dtype=ref.dtype)
245
+ for item in items
246
+ ]
247
+ return torch.cat(tensor_items, dim=axis)
248
+
249
+ return np.concatenate(items, axis=axis)
250
+
251
+
252
+ def _stack_array_or_tensor(items, axis=0):
253
+ """Stack while preserving tensor/array type and device."""
254
+ if not items:
255
+ return None
256
+
257
+ if any(isinstance(item, torch.Tensor) for item in items):
258
+ ref = next(item for item in items if isinstance(item, torch.Tensor))
259
+ tensor_items = [
260
+ item
261
+ if isinstance(item, torch.Tensor)
262
+ else torch.as_tensor(item, device=ref.device, dtype=ref.dtype)
263
+ for item in items
264
+ ]
265
+ return torch.stack(tensor_items, dim=axis)
266
+
267
+ return np.stack(items, axis=axis)
268
+
269
+
270
  class MossVLImagesKwargs(ImagesKwargs):
271
  min_pixels: Optional[int]
272
  max_pixels: Optional[int]
 
309
  r"""
310
  Constructs a Moss-VL processor which wraps a Qwen2VL image processor, Moss-VL video processor and a Qwen2 tokenizer
311
  into a single processor.
 
312
  [`MossVLProcessor`] offers all the functionalities of [`Qwen2VLImageProcessor`], [`MossVLVideoProcessor`] and [`Qwen2TokenizerFast`].
313
  See the [`~MossVLProcessor.__call__`] and [`~MossVLProcessor.decode`] for more information.
 
314
  Args:
315
  image_processor ([`Qwen2VLImageProcessor`], *optional*):
316
  The image processor is a required input.
 
323
  """
324
 
325
  attributes = ["image_processor", "tokenizer", "video_processor"]
 
 
326
  tokenizer_class = ("Qwen2Tokenizer", "Qwen2TokenizerFast")
327
 
328
  def __init__(
 
387
  ) -> BatchFeature:
388
  """
389
  Main method to prepare for the model one or several sequences(s) and image(s)/video(s).
 
390
  Args:
391
  text (`str`, `list[str]`, `list[list[str]]`):
392
  The sequence or batch of sequences to be encoded.
 
418
  - `'pt'`: Return PyTorch `torch.Tensor` objects.
419
  - `'np'`: Return NumPy `np.ndarray` objects.
420
  - `'jax'`: Return JAX `jnp.ndarray` objects.
 
 
421
  Returns:
422
  [`BatchFeature`]: A [`BatchFeature`] with the following fields:
423
  - **input_ids** -- List of token ids to be fed to a model.
 
531
  elif len(patch_counts) > 1:
532
  # Multiple images: split by cumulative counts
533
  split_indices = np.cumsum(patch_counts)[:-1]
534
+ image_pixel_values_list = _split_array_or_tensor(
535
+ flat_pixel_values, split_indices
536
+ )
537
 
538
  if has_videos:
539
  flat_video_values = videos_inputs["pixel_values_videos"]
 
545
  elif len(video_patch_counts) > 1:
546
  # Multiple videos: split by cumulative counts
547
  split_indices = np.cumsum(video_patch_counts)[:-1]
548
+ video_pixel_values_list = _split_array_or_tensor(
549
+ flat_video_values, split_indices
550
+ )
551
 
552
  # Step 3.1: Replace placeholders (simple replacement, no expansion yet)
553
  # In MossVL, one image placeholder = one image token
 
763
 
764
  # Concatenate/stack to unified format
765
  if final_pixel_values:
766
+ output_data["pixel_values"] = _concat_array_or_tensor(
767
+ final_pixel_values, axis=0
768
+ )
769
 
770
  if final_grid_thw:
771
+ output_data["grid_thw"] = _stack_array_or_tensor(
772
+ final_grid_thw, axis=0
773
+ )
774
 
775
  # Don't add media_nums_per_sample to output_data yet
776
  # Will add it after BatchFeature to keep it as list
 
827
  for _ in range(num_media):
828
  # grid_thw is (N, 3) where first dim is t (num_frames)
829
  t = grid_thw[media_idx][0]
830
+ if isinstance(t, torch.Tensor):
831
+ t = int(t.item())
832
+ else:
833
+ t = int(t)
834
  sample_frames += t
835
  media_idx += 1
836
  total_frames_per_sample.append(sample_frames)
 
1111
  ):
1112
  """
1113
  Post-process the output of the model to decode the text.
 
1114
  Args:
1115
  generated_outputs (`torch.Tensor` or `np.ndarray`):
1116
  The output of the model `generate` function. The output is expected to be a tensor
 
1121
  Whether or not to clean up the tokenization spaces.
1122
  **kwargs:
1123
  Additional arguments to be passed to the tokenizer's `batch_decode` method.
 
1124
  Returns:
1125
  `list[str]`: The decoded text.
1126
  """
 
1131
  **kwargs,
1132
  )
1133
 
1134
+ __all__ = ["MossVLProcessor", "MossVLImageProcessor"]