[Bugfix] Fix Compatibility of Ming-flash-omni-2.0 on transformers 5.X and vllm 0.22 (#4080)

Signed-off-by: Yuanheng Zhao <jonathan.zhaoyh@gmail.com>
Signed-off-by: akshatvishu <akshatnayak197@gmail.com>
Co-authored-by: akshatvishu <akshatnayak197@gmail.com>
This commit is contained in:
Yuanheng Zhaoandakshatvishu authored and GitHub committed 2026-06-05 09:27:42 +08:00
1 parent 6e8ef213d8
commit 95d56cf062
6 files changed
+97 -26

No files matched your search

+9 -6
View File
@@ -57,12 +57,6 @@ Adjust `devices` in the YAML to match your hardware.
#### Command
Thinker only (text output):
```bash
vllm serve Jonathan1909/Ming-flash-omni-2.0 --omni --port 8091
```
Thinker + talker (text and/or audio output):
```bash
@@ -72,6 +66,15 @@ vllm serve Jonathan1909/Ming-flash-omni-2.0 \
--log-stats
```
Thinker only (text-only output):
```bash
vllm serve Jonathan1909/Ming-flash-omni-2.0 \
--omni \
--deploy-config vllm_omni/deploy/ming_flash_omni_thinker_only.yaml \
--port 8091
```
`--log-stats` is optional but recommended while validating the deployment.
#### Verification
@@ -72,6 +72,7 @@ from vllm_omni.transformers_utils.processors.ming import (
PLACEHOLDER_VIDEO_TOKEN_IN_TEXT,
MingFlashOmniProcessor,
MingWhisperFeatureExtractor,
raise_missing_video_processor,
)
from .audio_encoder import WhisperAudioEncoder
@@ -540,20 +541,20 @@ class MingFlashOmniThinkerMultiModalProcessor(BaseMultiModalProcessor[MingFlashO
if images is not None:
image_outputs = hf_processor.image_processor(
images=images,
videos=None,
return_tensors="pt",
)
data.update(image_outputs)
videos = mm_data.get("videos", None)
if videos is not None:
# TODO: ``videos=`` on image_processor is deprecated since
# transformers v4.57 (removed in v5); migrate to Qwen2VLVideoProcessor.
video_outputs = hf_processor.image_processor(
images=None,
videos=videos,
return_tensors="pt",
)
video_processor = getattr(hf_processor, "video_processor", None)
if video_processor is not None:
video_outputs = video_processor(
videos=videos,
return_tensors="pt",
)
else:
raise_missing_video_processor()
# Rename keys to distinguish from images
if "pixel_values" in video_outputs:
video_outputs["pixel_values_videos"] = video_outputs.pop("pixel_values")
@@ -714,6 +714,9 @@ class BailingMoeV2Model(nn.Module):
def get_input_embeddings(self):
return self.word_embeddings
def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
return self.word_embeddings(input_ids)
def forward(
self,
input_ids: torch.Tensor,
@@ -794,6 +797,9 @@ class BailingMoeV2ForCausalLM(nn.Module, CustomProcessMixin):
self.sampler = Sampler()
self.make_empty_intermediate_tensors = self.model.make_empty_intermediate_tensors
def embed_input_ids(self, input_ids: torch.Tensor) -> torch.Tensor:
return self.model.embed_input_ids(input_ids)
def forward(
self,
input_ids: torch.Tensor,
@@ -818,7 +824,7 @@ class BailingMoeV2ForCausalLM(nn.Module, CustomProcessMixin):
hidden_states: torch.Tensor,
sampling_metadata,
) -> torch.Tensor | None:
logits = self.logits_processor(self.lm_head, hidden_states, sampling_metadata)
logits = self.logits_processor(self.lm_head, hidden_states)
return logits
def sample(
@@ -902,6 +902,7 @@ class MingAudioGenerator:
if self._audio_vae is None:
return requested_max_steps
# Transformers >=5.x may expose these config values as 0-d tensors.
sample_rate = float(self._audio_vae.config.sample_rate)
vae_patch_size = float(getattr(self._audio_vae.config, "patch_size", 4))
hop_size = float(getattr(self._audio_vae.decoder, "hop_length", 320))
@@ -1041,7 +1042,7 @@ class MingAudioGenerator:
use_cache=True,
)
else:
past_seen_tokens = past_key_values.get_seq_length()
past_seen_tokens = int(past_key_values.get_seq_length())
cache_position = torch.arange(
past_seen_tokens,
past_seen_tokens + inputs_embeds.shape[1],
@@ -27,6 +27,7 @@ logger = logging.get_logger(__name__)
class BailingMoeV2Config(PretrainedConfig):
model_type = "bailing_moe_v2"
ignore_keys_at_rope_validation = {"mrope_section"}
def __init__(
self,
@@ -237,6 +238,7 @@ class WhisperEncoderConfig(PretrainedConfig):
class BailingMM2Config(PretrainedConfig):
model_type = "bailingmm_moe_v2_lite"
ignore_keys_at_rope_validation = {"mrope_section"}
is_composition = True
sub_configs: ClassVar = {"llm_config": AutoConfig}
@@ -352,9 +354,13 @@ class MingFlashOmniTalkerConfig(PretrainedConfig):
self.campplus_model = campplus_model
def get_text_config(self, decoder: bool = False) -> PretrainedConfig: # noqa: ARG002
if isinstance(self.llm_config, dict):
return PretrainedConfig.from_dict(self.llm_config)
return self.llm_config
# NOTE: transformers v5 runs validators (e.g. validate_token_ids -> get_text_config)
# during PretrainedConfig.__init__, before llm_config is assigned
llm_config = getattr(self, "llm_config", None)
if isinstance(llm_config, dict):
return PretrainedConfig.from_dict(llm_config)
return llm_config
class MingFlashOmniConfig(PretrainedConfig):
@@ -22,6 +22,21 @@ from transformers import AutoFeatureExtractor, AutoProcessor
from transformers.feature_extraction_utils import BatchFeature, FeatureExtractionMixin
from transformers.processing_utils import ProcessorMixin
from transformers.tokenization_utils_base import PreTokenizedInput, TextInput
from transformers.utils import logging
try:
from transformers import AutoVideoProcessor
except ImportError:
AutoVideoProcessor = None
_HAS_VIDEO_PROCESSOR = AutoVideoProcessor is not None
logger = logging.get_logger(__name__)
def raise_missing_video_processor():
raise ValueError("Ming Flash Omni video inputs require a Transformers 5.x `video_processor`.")
DEFAULT_IMAGE_PATCH_TOKEN = "<imagePatch>"
DEFAULT_IM_START_TOKEN = "<image>"
@@ -156,6 +171,8 @@ class MingFlashOmniProcessor(ProcessorMixin):
attributes = ["image_processor", "audio_processor", "tokenizer"]
image_processor_class = "AutoImageProcessor"
if _HAS_VIDEO_PROCESSOR:
video_processor_class = "AutoVideoProcessor"
audio_processor_class = "AutoFeatureExtractor"
tokenizer_class = "AutoTokenizer"
@@ -167,6 +184,7 @@ class MingFlashOmniProcessor(ProcessorMixin):
merge_size: int = 2,
**kwargs,
):
video_processor = kwargs.pop("video_processor", None)
# Enforce that all sub-processors exist
# Keep None defaults in the signature for HF ProcessorMixin compatibility
if image_processor is None:
@@ -180,16 +198,47 @@ class MingFlashOmniProcessor(ProcessorMixin):
self.image_token = PLACEHOLDER_IMAGE_TOKEN_IN_TEXT
self.video_token = PLACEHOLDER_VIDEO_TOKEN_IN_TEXT
self.audio_token = PLACEHOLDER_AUDIO_TOKEN_IN_TEXT
if video_processor is not None and not _HAS_VIDEO_PROCESSOR:
raise ValueError("`video_processor` requires transformers with `AutoVideoProcessor` support.")
super().__init__(
image_processor=image_processor,
audio_processor=audio_processor,
tokenizer=tokenizer,
)
self.video_processor = video_processor
# Fall back to the tokenizer's own chat_template.
if self.chat_template is None:
self.chat_template = getattr(tokenizer, "chat_template", None)
@classmethod
def from_pretrained(cls, pretrained_model_name_or_path, *args, **kwargs):
video_processor = kwargs.pop("video_processor", None)
processor = super().from_pretrained(pretrained_model_name_or_path, *args, **kwargs)
if video_processor is not None:
processor.video_processor = video_processor
elif _HAS_VIDEO_PROCESSOR:
try:
processor.video_processor = AutoVideoProcessor.from_pretrained(
pretrained_model_name_or_path,
*args,
**kwargs,
)
except OSError:
processor.video_processor = None
except (ValueError, KeyError) as exc:
logger.warning("Failed to load optional Ming video processor: %s", exc)
processor.video_processor = None
return processor
def save_pretrained(self, save_directory, push_to_hub: bool = False, **kwargs):
output = super().save_pretrained(save_directory, push_to_hub=push_to_hub, **kwargs)
video_processor = getattr(self, "video_processor", None)
if video_processor is not None:
video_processor.save_pretrained(save_directory)
return output
def __call__(
self,
text: TextInput | PreTokenizedInput | list[TextInput] | list[PreTokenizedInput],
@@ -211,7 +260,6 @@ class MingFlashOmniProcessor(ProcessorMixin):
if images is not None:
image_outputs = self.image_processor(
images=images,
videos=None,
return_tensors="pt",
**kwargs.get("images_kwargs", {}),
)
@@ -220,12 +268,15 @@ class MingFlashOmniProcessor(ProcessorMixin):
text = self._expand_image_tokens(text, image_outputs["image_grid_thw"])
if videos is not None:
video_outputs = self.image_processor(
images=None,
videos=videos,
return_tensors="pt",
**kwargs.get("videos_kwargs", {}),
)
video_processor = getattr(self, "video_processor", None)
if video_processor is not None:
video_outputs = video_processor(
videos=videos,
return_tensors="pt",
**kwargs.get("videos_kwargs", {}),
)
else:
raise_missing_video_processor()
if "pixel_values" in video_outputs:
video_outputs["pixel_values_videos"] = video_outputs.pop("pixel_values")
if "image_grid_thw" in video_outputs:
@@ -423,6 +474,9 @@ class MingFlashOmniProcessor(ProcessorMixin):
+ self.image_processor.model_input_names
+ self.audio_processor.model_input_names
)
video_processor = getattr(self, "video_processor", None)
if video_processor is not None:
names += video_processor.model_input_names
return list(dict.fromkeys(names))