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

#3
by Joiin0392 - opened
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
 
@@ -3596,7 +3604,16 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
3596
  and buf_list[-1] == invalid_token_id
3597
  )
3598
  if is_silence_or_ellipsis or is_complete_text or is_invalid_complete:
3599
- output_text_queue.put(decoded_text)
 
 
 
 
 
 
 
 
 
3600
  token_buffer.clear()
3601
 
3602
  input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)
 
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
 
 
3604
  and buf_list[-1] == invalid_token_id
3605
  )
3606
  if is_silence_or_ellipsis or is_complete_text or is_invalid_complete:
3607
+ # The end-of-buffer guard above only catches an INCOMPLETE
3608
+ # trailing char. Under sampling, a multi-byte char can also
3609
+ # break MID-string (the next token completes a different
3610
+ # char, orphaning the first char's tail bytes) — the
3611
+ # replacement char then stays in the text forever. Those
3612
+ # bytes are unrecoverable at this point: drop the broken
3613
+ # character instead of emitting mojibake.
3614
+ clean_text = decoded_text.replace("\ufffd", "")
3615
+ if clean_text:
3616
+ output_text_queue.put(clean_text)
3617
  token_buffer.clear()
3618
 
3619
  input_ids = torch.cat([input_ids, next_tokens[:, None]], dim=-1)
processing_moss_vl.py CHANGED
@@ -164,12 +164,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
 
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
+ # NPU ops support at most 8-D tensors; route the 10-D permute+reshape
168
+ # through CPU there. CUDA handles 10-D natively — keep it on-device.
169
+ patches_device = patches.device
170
+ if patches_device.type == "npu":
171
+ patches = patches.cpu()
172
  patches = patches.permute(0, 1, 4, 7, 5, 8, 3, 2, 6, 9)
173
  flatten_patches = patches.reshape(
174
  batch_size,
175
  grid_t * grid_h * grid_w,
176
  channel * temporal_patch_size * patch_size * patch_size,
177
+ ).to(patches_device)
178
 
179
  processed_images_grouped[shape] = flatten_patches
180
  processed_grids[shape] = [[grid_t, grid_h, grid_w]] * batch_size
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