Instructions to use OpenMOSS-Team/MOSS-VL-Realtime with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use OpenMOSS-Team/MOSS-VL-Realtime with Transformers:
# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("OpenMOSS-Team/MOSS-VL-Realtime", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Ascend NPU support: device-aware cache release, GIL-friendly idle wait, <=8-D vision processing, BICUBIC declaration
Browse filesAscend 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 +12 -4
- preprocessor_config.json +2 -1
- processing_moss_vl.py +23 -14
- video_processing_moss_vl.py +6 -1
|
@@ -2874,8 +2874,13 @@ class MossVLForConditionalGeneration(MossVLPreTrainedModel, GenerationMixin):
|
|
| 2874 |
|
| 2875 |
def stop_real_time_generate(self):
|
| 2876 |
gc.collect()
|
| 2877 |
-
|
| 2878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
#
|
| 3103 |
-
#
|
|
|
|
|
|
|
|
|
|
| 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 |
|
|
@@ -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 |
}
|
|
@@ -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):
|
|
@@ -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
|