Joiin0392 commited on
Commit
5c67b2b
·
verified ·
1 Parent(s): 06b0676

Ascend NPU support: device-aware cache release, GIL-friendly idle wait, <=8-D vision processing, BICUBIC declaration

Browse files

Ascend NPU (910B, CANN 9.0.0) support for the realtime checkpoint.
CUDA behavior unchanged — every NPU path is guarded.

- modeling_moss_vl.py
- empty_cache: release NPU HBM after realtime sessions (torch_npu import
guarded; the CUDA branch is unchanged)
- realtime idle wait: a bare `while True: continue` busy-spin monopolizes
the CPython GIL and starves co-resident threads (measured: an in-process
ASR decode inflates ~150ms -> 40-80s while a session idles in
<|silence|>). Replaced with a 20ms sleep poll. Platform-neutral — CUDA
deployments embedding this checkpoint benefit equally.
- processing / video_processing: the 10-D vision permute+reshape is routed
through CPU on NPU (NPU ops support at most 8-D tensors); CUDA keeps the
on-device path untouched.
- preprocessor_config.json: declare interpolation=BICUBIC explicitly (NPU has
no implicit resize kernel; explicit declaration keeps CUDA outputs
identical — pixel_values verified bitwise-equal on identical inputs,
including forced-resize cases).

Verified on 910B2C x8 with the realtime demo (ASR/TTS/VLM E2E green); the
GIL fix restores in-process ASR latency from 52.5s to ~150ms.

modeling_moss_vl.py CHANGED
@@ -2874,8 +2874,13 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
2874
 
2875
  def stop_real_time_generate(self):
2876
  gc.collect()
2877
- if torch.cuda.is_available():
2878
- torch.cuda.empty_cache()
 
 
 
 
 
2879
  self.continue_generating = False
2880
 
2881
  @staticmethod
@@ -3099,8 +3104,11 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
3099
  break
3100
 
3101
  if self.continue_generating and should_wait_for_new_input and not frames_to_process and not prompts_to_process:
3102
- # Busy-wait — matches VideoMllama reference. Caller controls cadence via
3103
- # `max_tokens_per_turn` sleeping in `_real_time_sample`.
 
 
 
3104
  continue
3105
  break
3106
 
 
2874
 
2875
  def stop_real_time_generate(self):
2876
  gc.collect()
2877
+ try:
2878
+ import torch_npu # noqa: F401
2879
+ if torch.npu.is_available():
2880
+ torch.npu.empty_cache()
2881
+ except ImportError:
2882
+ if torch.cuda.is_available():
2883
+ torch.cuda.empty_cache()
2884
  self.continue_generating = False
2885
 
2886
  @staticmethod
 
3104
  break
3105
 
3106
  if self.continue_generating and should_wait_for_new_input and not frames_to_process and not prompts_to_process:
3107
+ # GIL-friendly wait: a bare `continue` busy-spin monopolizes the GIL
3108
+ # and starves in-process siblings (in-process ASR decode inflates
3109
+ # ~150ms -> 40-80s while a realtime session idles in <|silence|>).
3110
+ # 20ms poll keeps input-detection latency negligible.
3111
+ time.sleep(0.02)
3112
  continue
3113
  break
3114
 
preprocessor_config.json CHANGED
@@ -22,5 +22,6 @@
22
  0.5
23
  ],
24
  "processor_class": "MossVLProcessor",
25
- "image_processor_type": "MossVLImageProcessorFast"
 
26
  }
 
22
  0.5
23
  ],
24
  "processor_class": "MossVLProcessor",
25
+ "image_processor_type": "MossVLImageProcessorFast",
26
+ "interpolation": "BICUBIC"
27
  }
processing_moss_vl.py CHANGED
@@ -49,24 +49,28 @@ class MossVLImageProcessorFast(Qwen2VLImageProcessorFast):
49
  """
50
  # Multi-image batch total pixels limit (read from config)
51
  multi_image_max_pixels = None
52
-
 
 
 
 
53
 
54
  def _preprocess(
55
  self,
56
  images: list["torch.Tensor"],
57
  do_resize: bool,
58
  size: SizeDict,
59
- interpolation: Optional["F.InterpolationMode"],
60
- do_rescale: bool,
61
- rescale_factor: float,
62
- do_normalize: bool,
63
- image_mean: Optional[Union[float, list[float]]],
64
- image_std: Optional[Union[float, list[float]]],
65
- patch_size: int,
66
- temporal_patch_size: int,
67
- merge_size: int,
68
- disable_grouping: Optional[bool],
69
- return_tensors: Optional[Union[str, TensorType]],
70
  **kwargs,
71
  ):
72
  """Override _preprocess to use custom smart_resize with batch-level max_pixels.
@@ -164,12 +168,17 @@ class MossVLImageProcessorFast(Qwen2VLImageProcessorFast):
164
  )
165
  # Reorder dimensions to group grid and patch information for subsequent flattening.
166
  # (batch, grid_t, grid_h, grid_w, merge_h, merge_w, channel, temp_patch_size, patch_h, patch_w)
 
 
 
 
 
167
  patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
168
  flatten_patches = patches.reshape(
169
  batch_size,
170
  grid_t * grid_h * grid_w,
171
  channel * temporal_patch_size * patch_size * patch_size,
172
- )
173
 
174
  processed_images_grouped[shape] = flatten_patches
175
  processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
@@ -272,7 +281,7 @@ class MossVLImagesKwargs(ImagesKwargs):
272
  patch_size: Optional[int]
273
  temporal_patch_size: Optional[int]
274
  merge_size: Optional[int]
275
-
276
 
277
 
278
  class MossVLVideosKwargs(VideosKwargs, total=False):
 
49
  """
50
  # Multi-image batch total pixels limit (read from config)
51
  multi_image_max_pixels = None
52
+
53
+ def __init__(self, *args, **kwargs):
54
+ super().__init__(*args, **kwargs)
55
+ if not hasattr(self, 'interpolation') or self.interpolation is None:
56
+ self.interpolation = "BICUBIC"
57
 
58
  def _preprocess(
59
  self,
60
  images: list["torch.Tensor"],
61
  do_resize: bool,
62
  size: SizeDict,
63
+ interpolation: Optional["F.InterpolationMode"] = None,
64
+ do_rescale: bool = True,
65
+ rescale_factor: float = 1 / 255,
66
+ do_normalize: bool = True,
67
+ image_mean: Optional[Union[float, list[float]]] = None,
68
+ image_std: Optional[Union[float, list[float]]] = None,
69
+ patch_size: int = 16,
70
+ temporal_patch_size: int = 1,
71
+ merge_size: int = 2,
72
+ disable_grouping: Optional[bool] = None,
73
+ return_tensors: Optional[Union[str, TensorType]] = None,
74
  **kwargs,
75
  ):
76
  """Override _preprocess to use custom smart_resize with batch-level max_pixels.
 
168
  )
169
  # Reorder dimensions to group grid and patch information for subsequent flattening.
170
  # (batch, grid_t, grid_h, grid_w, merge_h, merge_w, channel, temp_patch_size, patch_h, patch_w)
171
+ # NPU supports max 8D tensors; route the 10D permute+reshape through
172
+ # CPU there. CUDA handles 10D natively — keep it on-device.
173
+ patches_device = patches.device
174
+ if patches_device.type == "npu":
175
+ patches = patches.cpu()
176
  patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
177
  flatten_patches = patches.reshape(
178
  batch_size,
179
  grid_t * grid_h * grid_w,
180
  channel * temporal_patch_size * patch_size * patch_size,
181
+ ).to(patches_device)
182
 
183
  processed_images_grouped[shape] = flatten_patches
184
  processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
 
281
  patch_size: Optional[int]
282
  temporal_patch_size: Optional[int]
283
  merge_size: Optional[int]
284
+ interpolation: Optional[str]
285
 
286
 
287
  class MossVLVideosKwargs(VideosKwargs, total=False):
video_processing_moss_vl.py CHANGED
@@ -1147,12 +1147,17 @@ class MossVLVideoProcessor(BaseVideoProcessor):
1147
  merge_size,
1148
  patch_size,
1149
  )
 
 
 
 
 
1150
  patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
1151
  flatten_patches = patches.reshape(
1152
  batch_size,
1153
  grid_t * grid_h * grid_w,
1154
  channel * temporal_patch_size * patch_size * patch_size,
1155
- )
1156
 
1157
  processed_videos_grouped[shape] = flatten_patches
1158
  processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
 
1147
  merge_size,
1148
  patch_size,
1149
  )
1150
+ patches_device = patches.device
1151
+ # NPU: max 8D tensors — route the 10D permute+reshape through CPU.
1152
+ # CUDA handles 10D natively — keep it on-device.
1153
+ if patches_device.type == "npu":
1154
+ patches = patches.cpu()
1155
  patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
1156
  flatten_patches = patches.reshape(
1157
  batch_size,
1158
  grid_t * grid_h * grid_w,
1159
  channel * temporal_patch_size * patch_size * patch_size,
1160
+ ).to(patches_device)
1161
 
1162
  processed_videos_grouped[shape] = flatten_patches
1163
  processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size