[Model] Remove AyaVision, MusicFlamingo (#47263)
Signed-off-by: Harry Mellor <19981378+hmellor@users.noreply.github.com>
Harry Mellor committed
Jul 1, 2026 at 11:39 UTC
a22e0dfc69a0fe9e058ccea865fbc4868bb187e1
12 files changed
+3
-1422
docs/models/supported_models.md
-2
@@ -532,7 +532,6 @@ These models primarily accept the [`LLM.generate`](./generative_models.md#llmgen
532
| ------------ | ------ | ------ | ----------------- | -------------------- | ------------------------- |
533
| `AriaForConditionalGeneration` | Aria | T + I<sup>+</sup> | `rhymes-ai/Aria` | | |
534
| `AudioFlamingo3ForConditionalGeneration` | AudioFlamingo3 | T + A | `nvidia/audio-flamingo-3-hf`, `nvidia/music-flamingo-hf` | ✅︎ | ✅︎ |
535
-| `AyaVisionForConditionalGeneration` | Aya Vision | T + I<sup>+</sup> | `CohereLabs/aya-vision-8b`, `CohereLabs/aya-vision-32b`, etc. | | ✅︎ |
535
| `BagelForConditionalGeneration` | BAGEL | T + I<sup>+</sup> | `ByteDance-Seed/BAGEL-7B-MoT` | ✅︎ | ✅︎ |
536
| `BeeForConditionalGeneration` | Bee-8B | T + I<sup>E+</sup> | `Open-Bee/Bee-8B-RL`, `Open-Bee/Bee-8B-SFT` | | ✅︎ |
537
| `Blip2ForConditionalGeneration` | BLIP-2 | T + I<sup>E</sup> | `Salesforce/blip2-opt-2.7b`, `Salesforce/blip2-opt-6.7b`, etc. | ✅︎ | ✅︎ |
@@ -594,7 +593,6 @@ These models primarily accept the [`LLM.generate`](./generative_models.md#llmgen
593
| `Molmo2ForConditionalGeneration` | Molmo2 | T + I<sup>+</sup> / V | `allenai/Molmo2-4B`, `allenai/Molmo2-8B`, `allenai/Molmo2-O-7B`, `allenai/MolmoWeb-4B`<sup>^</sup>, `allenai/MolmoWeb-8B`<sup>^</sup> | ✅︎ | ✅︎ |
594
| `MossAudioModel` | MOSS-Audio | T + A<sup>+</sup> | `OpenMOSS-Team/MOSS-Audio-4B-Instruct`, `OpenMOSS-Team/MOSS-Audio-4B-Thinking`, `OpenMOSS-Team/MOSS-Audio-8B-Instruct`, `OpenMOSS-Team/MOSS-Audio-8B-Thinking` | ✅︎ | ✅︎ |
595
| `Moondream3ForCausalLM` | Moondream3 | T + I | `moondream/moondream3-preview` | | ✅︎ |
597
-| `MusicFlamingoForConditionalGeneration` | MusicFlamingo | T + A | `nvidia/music-flamingo-2601-hf`, `nvidia/music-flamingo-think-2601-hf` | ✅︎ | ✅︎ |
596
| `NVLM_D_Model` | NVLM-D 1.0 | T + I<sup>+</sup> | `nvidia/NVLM-D-72B`, etc. | | ✅︎ |
597
| `OpenCUAForConditionalGeneration` | OpenCUA-7B | T + I<sup>E+</sup> | `xlangai/OpenCUA-7B` | ✅︎ | ✅︎ |
598
| `OpenPanguVLForConditionalGeneration` | openpangu-VL | T + I<sup>E+</sup> + V<sup>E+</sup> | `FreedomIntelligence/openPangu-VL-7B` | ✅︎ | ✅︎ |
examples/generate/multimodal/audio_language_offline.py
-39
@@ -91,44 +91,6 @@ def run_cohere_asr(question: str, audio_count: int) -> ModelRequestData:
91
)
92
93
94
-# MusicFlamingo
95
-def run_musicflamingo(question: str, audio_count: int) -> ModelRequestData:
96
- model_name = "nvidia/music-flamingo-2601-hf"
97
- engine_args = EngineArgs(
98
- model=model_name,
99
- max_model_len=4096,
100
- max_num_seqs=2,
101
- limit_mm_per_prompt={"audio": audio_count},
102
- enforce_eager=True,
103
- )
104
-
105
- # MusicFlamingo prompt placeholders use <sound>; vLLM's MusicFlamingo
106
- # multimodal processor expands each one into <|sound_bos|> + audio tokens +
107
- # <|sound_eos|> based on extracted audio feature lengths.
108
- audio_placeholder = "<sound>" * audio_count
109
- system_prompt = (
110
- "You are Music Flamingo, a multimodal assistant for language and music. "
111
- "On each turn you receive an audio clip which contains music and optional "
112
- "text, you will receive at least one or both; use your world knowledge and "
113
- "reasoning to help the user with any task. Interpret the entirety of the "
114
- "content any input music--regardlenss of whether the user calls it audio, "
115
- "music, or sound."
116
- )
117
-
118
- prompt = (
119
- "<|im_start|>system\n"
120
- f"{system_prompt}<|im_end|>\n"
121
- "<|im_start|>user\n"
122
- f"{audio_placeholder}{question}<|im_end|>\n"
123
- "<|im_start|>assistant\n"
124
- )
125
-
126
- return ModelRequestData(
127
- engine_args=engine_args,
128
- prompt=prompt,
129
- )
130
-
131
-
94
# Gemma3N
95
def run_gemma3n(question: str, audio_count: int) -> ModelRequestData:
96
model_name = "google/gemma-3n-E2B-it"
@@ -565,7 +527,6 @@ model_example_map = {
527
"kimi_audio": run_kimi_audio,
528
"midashenglm": run_midashenglm,
529
"minicpmo": run_minicpmo,
568
- "musicflamingo": run_musicflamingo,
530
"phi4_mm": run_phi4mm,
531
"qwen2_audio": run_qwen2_audio,
532
"qwen2_5_omni": run_qwen2_5_omni,
examples/generate/multimodal/vision_language_multi_image_offline.py
-34
@@ -74,39 +74,6 @@ def load_aria(question: str, image_urls: list[str]) -> ModelRequestData:
74
)
75
76
77
-def load_aya_vision(question: str, image_urls: list[str]) -> ModelRequestData:
78
- model_name = "CohereLabs/aya-vision-8b"
79
-
80
- engine_args = EngineArgs(
81
- model=model_name,
82
- max_num_seqs=2,
83
- limit_mm_per_prompt={"image": len(image_urls)},
84
- )
85
-
86
- placeholders = [{"type": "image", "image": url} for url in image_urls]
87
- messages = [
88
- {
89
- "role": "user",
90
- "content": [
91
- *placeholders,
92
- {"type": "text", "text": question},
93
- ],
94
- }
95
- ]
96
-
97
- processor = AutoProcessor.from_pretrained(model_name)
98
-
99
- prompt = processor.apply_chat_template(
100
- messages, tokenize=False, add_generation_prompt=True
101
- )
102
-
103
- return ModelRequestData(
104
- engine_args=engine_args,
105
- prompt=prompt,
106
- image_data=[fetch_image(url) for url in image_urls],
107
- )
108
-
109
-
77
def load_bee(question: str, image_urls: list[str]) -> ModelRequestData:
78
model_name = "Open-Bee/Bee-8B-RL"
79
@@ -1420,7 +1387,6 @@ def load_molmo2(question: str, image_urls: list[str]) -> ModelRequestData:
1387
1388
model_example_map = {
1389
"aria": load_aria,
1423
- "aya_vision": load_aya_vision,
1390
"bee": load_bee,
1391
"command_a_vision": load_command_a_vision,
1392
"deepseek_vl_v2": load_deepseek_vl2,
examples/generate/multimodal/vision_language_offline.py
-23
@@ -68,28 +68,6 @@ def run_aria(questions: list[str], modality: str) -> ModelRequestData:
68
)
69
70
71
-# Aya Vision
72
-def run_aya_vision(questions: list[str], modality: str) -> ModelRequestData:
73
- assert modality == "image"
74
- model_name = "CohereLabs/aya-vision-8b"
75
-
76
- engine_args = EngineArgs(
77
- model=model_name,
78
- max_model_len=2048,
79
- max_num_seqs=2,
80
- mm_processor_kwargs={"crop_to_patches": True},
81
- limit_mm_per_prompt={modality: 1},
82
- )
83
- prompts = [
84
- f"<|START_OF_TURN_TOKEN|><|USER_TOKEN|><image>{question}<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>"
85
- for question in questions
86
- ]
87
- return ModelRequestData(
88
- engine_args=engine_args,
89
- prompts=prompts,
90
- )
91
-
92
-
71
# Bee-8B
72
def run_bee(questions: list[str], modality: str) -> ModelRequestData:
73
assert modality == "image"
@@ -2327,7 +2305,6 @@ def run_step_vl(questions: list[str], modality: str) -> ModelRequestData:
2305
2306
model_example_map = {
2307
"aria": run_aria,
2330
- "aya_vision": run_aya_vision,
2308
"bagel": run_bagel,
2309
"cheers": run_cheers,
2310
"bee": run_bee,
tests/models/multimodal/generation/test_common.py
-33
@@ -326,39 +326,6 @@ VLM_TEST_SETTINGS = {
326
large_gpu_mark(min_gb=64),
327
],
328
),
329
- "aya_vision": VLMTestInfo(
330
- models=["CohereLabs/aya-vision-8b"],
331
- test_type=(VLMTestType.IMAGE),
332
- prompt_formatter=lambda img_prompt: f"<|START_OF_TURN_TOKEN|><|USER_TOKEN|>{img_prompt}<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>", # noqa: E501
333
- single_image_prompts=IMAGE_ASSETS.prompts(
334
- {
335
- "stop_sign": "<image>What's the content in the center of the image?",
336
- "cherry_blossom": "<image>What is the season?",
337
- }
338
- ),
339
- multi_image_prompt="<image><image>Describe the two images in detail.",
340
- max_model_len=4096,
341
- max_num_seqs=2,
342
- auto_cls=AutoModelForImageTextToText,
343
- vllm_runner_kwargs={"mm_processor_kwargs": {"crop_to_patches": True}},
344
- ),
345
- "aya_vision-multi_image": VLMTestInfo(
346
- models=["CohereLabs/aya-vision-8b"],
347
- test_type=(VLMTestType.MULTI_IMAGE),
348
- prompt_formatter=lambda img_prompt: f"<|START_OF_TURN_TOKEN|><|USER_TOKEN|>{img_prompt}<|END_OF_TURN_TOKEN|><|START_OF_TURN_TOKEN|><|CHATBOT_TOKEN|>", # noqa: E501
349
- single_image_prompts=IMAGE_ASSETS.prompts(
350
- {
351
- "stop_sign": "<image>What's the content in the center of the image?",
352
- "cherry_blossom": "<image>What is the season?",
353
- }
354
- ),
355
- multi_image_prompt="<image><image>Describe the two images in detail.",
356
- max_model_len=4096,
357
- max_num_seqs=2,
358
- auto_cls=AutoModelForImageTextToText,
359
- vllm_runner_kwargs={"mm_processor_kwargs": {"crop_to_patches": True}},
360
- marks=[large_gpu_mark(min_gb=32)],
361
- ),
329
"blip2": VLMTestInfo(
330
models=["Salesforce/blip2-opt-2.7b"],
331
test_type=VLMTestType.IMAGE,
tests/models/multimodal/generation/test_musicflamingo.py
deleted
-152
@@ -1,152 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-import json
5
-import os
6
-
7
-import pytest
8
-
9
-from tests.models.registry import HF_EXAMPLE_MODELS
10
-from vllm import LLM, SamplingParams
11
-
12
-MODEL_NAME = "nvidia/music-flamingo-2601-hf"
13
-SINGLE_CONVERSATION = [
14
- {
15
- "role": "user",
16
- "content": [
17
- {
18
- "type": "text",
19
- "text": "Describe this track in full detail - tell me the "
20
- "genre, tempo, and key, then dive into the instruments, "
21
- "production style, and overall mood it creates.",
22
- },
23
- {
24
- "type": "audio_url",
25
- "audio_url": {
26
- "url": "https://huggingface.co/datasets/nvidia/AudioSkills/"
27
- "resolve/main/assets/song_1.mp3",
28
- },
29
- },
30
- ],
31
- }
32
-]
33
-BATCHED_CONVERSATIONS = [
34
- SINGLE_CONVERSATION,
35
- [
36
- {
37
- "role": "user",
38
- "content": [
39
- {
40
- "type": "text",
41
- "text": "Generate a structured lyric sheet from the input music.",
42
- },
43
- {
44
- "type": "audio_url",
45
- "audio_url": {
46
- "url": "https://huggingface.co/datasets/nvidia/"
47
- "AudioSkills/resolve/main/assets/song_2.mp3",
48
- },
49
- },
50
- ],
51
- }
52
- ],
53
-]
54
-
55
-
56
-def get_fixture_path(filename):
57
- return os.path.join(
58
- os.path.dirname(__file__), "../../fixtures/musicflamingo", filename
59
- )
60
-
61
-
62
-def load_expected_fixture(filename):
63
- fixture_path = get_fixture_path(filename)
64
- with open(fixture_path) as f:
65
- return json.load(f)
66
-
67
-
68
-def assert_output_matches(output, expected_text, expected_token_ids):
69
- generated = output.outputs[0]
70
- assert generated.text == expected_text
71
- actual_token_ids = list(generated.token_ids)
72
- assert (
73
- actual_token_ids == expected_token_ids
74
- or actual_token_ids == expected_token_ids[:-1]
75
- or actual_token_ids[:-1] == expected_token_ids
76
- )
77
-
78
-
79
-@pytest.fixture(scope="module")
80
-def llm():
81
- model_info = HF_EXAMPLE_MODELS.get_hf_info("MusicFlamingoForConditionalGeneration")
82
- model_info.check_transformers_version(on_fail="skip")
83
-
84
- try:
85
- llm = LLM(
86
- model=MODEL_NAME,
87
- dtype="bfloat16",
88
- enforce_eager=True,
89
- max_model_len=8192,
90
- limit_mm_per_prompt={"audio": 1},
91
- )
92
- except Exception as e:
93
- pytest.skip(f"Failed to load model {MODEL_NAME}: {e}")
94
-
95
- # ROCm may compile decoder kernels on the first inference pass; warm up
96
- # once so exact fixture assertions cover the steady-state path.
97
- llm.chat(
98
- messages=SINGLE_CONVERSATION,
99
- sampling_params=SamplingParams(temperature=0.0, max_tokens=1),
100
- use_tqdm=False,
101
- )
102
-
103
- return llm
104
-
105
-
106
-def test_single_generation(llm):
107
- expected = load_expected_fixture("expected_results_single.json")
108
-
109
- outputs = llm.chat(
110
- messages=SINGLE_CONVERSATION,
111
- sampling_params=SamplingParams(temperature=0.0, max_tokens=50),
112
- )
113
-
114
- assert_output_matches(
115
- outputs[0],
116
- expected["transcriptions"][0],
117
- expected["token_ids"][0],
118
- )
119
-
120
-
121
-def test_batched_generation(llm):
122
- expected = load_expected_fixture("expected_results_batched.json")
123
-
124
- outputs = llm.chat(
125
- messages=BATCHED_CONVERSATIONS,
126
- sampling_params=SamplingParams(temperature=0.0, max_tokens=50),
127
- )
128
-
129
- for i, output in enumerate(outputs):
130
- assert_output_matches(
131
- output,
132
- expected["transcriptions"][i],
133
- expected["token_ids"][i],
134
- )
135
-
136
-
137
-def test_single_and_batched_generation_match(llm):
138
- sampling_params = SamplingParams(temperature=0.0, max_tokens=50)
139
-
140
- single_output = llm.chat(
141
- messages=SINGLE_CONVERSATION,
142
- sampling_params=sampling_params,
143
- )[0]
144
- batched_output = llm.chat(
145
- messages=BATCHED_CONVERSATIONS,
146
- sampling_params=sampling_params,
147
- )[0]
148
-
149
- assert single_output.outputs[0].text == batched_output.outputs[0].text
150
- assert list(single_output.outputs[0].token_ids) == list(
151
- batched_output.outputs[0].token_ids
152
- )
tests/models/multimodal/processing/test_musicflamingo.py
deleted
-228
@@ -1,228 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-# Copyright 2026 The vLLM team.
5
-# Copyright 2026 NVIDIA CORPORATION and the HuggingFace Inc. team. All rights
6
-# reserved.
7
-#
8
-# Licensed under the Apache License, Version 2.0 (the "License");
9
-# you may not use this file except in compliance with the License.
10
-# You may obtain a copy of the License at
11
-#
12
-# http://www.apache.org/licenses/LICENSE-2.0
13
-#
14
-# Unless required by applicable law or agreed to in writing, software
15
-# distributed under the License is distributed on an "AS IS" BASIS,
16
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
-# See the License for the specific language governing permissions and
18
-# limitations under the License.
19
-
20
-from importlib.metadata import version
21
-from unittest.mock import MagicMock
22
-
23
-import numpy as np
24
-import pytest
25
-import torch
26
-from packaging.version import Version
27
-from transformers import PretrainedConfig
28
-
29
-from tests.models.registry import HF_EXAMPLE_MODELS
30
-
31
-
32
-class MockMusicFlamingoConfig(PretrainedConfig):
33
- model_type = "musicflamingo"
34
-
35
- def __init__(self, **kwargs):
36
- super().__init__(**kwargs)
37
- self.audio_config = PretrainedConfig()
38
- self.text_config = PretrainedConfig()
39
-
40
-
41
-class MockMusicFlamingoProcessor:
42
- def __init__(self):
43
- self.audio_token = "<sound>"
44
- self.audio_token_id = 12345
45
- self.audio_bos_token = "<|sound_bos|>"
46
- self.audio_bos_token_id = 12346
47
- self.audio_eos_token = "<|sound_eos|>"
48
- self.audio_eos_token_id = 12347
49
- self.max_audio_len = 1200
50
- self.feature_extractor = MockFeatureExtractor()
51
-
52
- def __call__(self, text=None, audio=None, **kwargs):
53
- return {
54
- "input_ids": torch.tensor([[1, 2, 3]], dtype=torch.long),
55
- "input_features": torch.zeros((3, 80, 3000)),
56
- "input_features_mask": torch.ones((3, 3000), dtype=torch.long),
57
- }
58
-
59
-
60
-class MockFeatureExtractor:
61
- def __init__(self):
62
- self.sampling_rate = 16000
63
- self.chunk_length = 30
64
-
65
-
66
-@pytest.fixture
67
-def mock_ctx():
68
- config = MockMusicFlamingoConfig()
69
-
70
- ctx = MagicMock()
71
- ctx.get_hf_config.return_value = config
72
- ctx.get_hf_processor.return_value = MockMusicFlamingoProcessor()
73
- ctx.call_hf_processor.side_effect = lambda processor, data, kwargs: processor(
74
- **data, **kwargs
75
- )
76
- ctx.model_config.hf_config = config
77
- return ctx
78
-
79
-
80
-@pytest.fixture(autouse=True)
81
-def check_transformers_version():
82
- model_info = HF_EXAMPLE_MODELS.get_hf_info("MusicFlamingoForConditionalGeneration")
83
- model_info.check_transformers_version(on_fail="skip")
84
-
85
-
86
-def test_musicflamingo_chunk_counting_without_rote_timestamps(mock_ctx):
87
- from vllm.model_executor.models.musicflamingo import (
88
- MusicFlamingoDummyInputsBuilder,
89
- MusicFlamingoMultiModalProcessor,
90
- MusicFlamingoProcessingInfo,
91
- )
92
-
93
- info = MusicFlamingoProcessingInfo(mock_ctx)
94
- processor = MusicFlamingoMultiModalProcessor(
95
- info, MusicFlamingoDummyInputsBuilder(info)
96
- )
97
-
98
- sr = 16000
99
- audio_1 = np.zeros(30 * sr)
100
- audio_2 = np.zeros(45 * sr)
101
-
102
- mm_data = {"audio": [audio_1, audio_2]}
103
- prompt = "<|user|>Listen.<|end|>"
104
-
105
- processed = processor._call_hf_processor(prompt, mm_data, {}, {})
106
-
107
- chunk_counts = processed["chunk_counts"]
108
-
109
- assert chunk_counts.tolist() == [1, 2]
110
- assert "rote_timestamps" not in processed
111
- assert processed["feature_attention_mask"].shape == (3, 3000)
112
-
113
-
114
-def test_musicflamingo_dummy_text_uses_plain_audio_tokens(mock_ctx):
115
- from vllm.model_executor.models.musicflamingo import (
116
- MusicFlamingoDummyInputsBuilder,
117
- MusicFlamingoProcessingInfo,
118
- )
119
-
120
- info = MusicFlamingoProcessingInfo(mock_ctx)
121
- builder = MusicFlamingoDummyInputsBuilder(info)
122
-
123
- assert builder.get_dummy_text({"audio": 2}) == "<sound><sound>"
124
-
125
-
126
-@pytest.mark.skipif(
127
- Version(version("transformers")) >= Version("5.5"),
128
- reason="transformers v5.5 added native MusicFlamingoForConditionalGeneration "
129
- "with a different get_audio_features signature (requires input_ids)",
130
-)
131
-def test_musicflamingo_audio_feature_pipeline_matches_hf_small_config():
132
- from transformers.models.musicflamingo import (
133
- modeling_musicflamingo as hf_musicflamingo_modeling,
134
- )
135
- from transformers.models.musicflamingo.configuration_musicflamingo import (
136
- MusicFlamingoConfig,
137
- )
138
-
139
- from vllm.model_executor.models.audioflamingo3 import (
140
- _build_audio_encoder_attention_mask,
141
- _flatten_valid_audio_embeddings,
142
- )
143
- from vllm.model_executor.models.musicflamingo import (
144
- MusicFlamingoEncoder,
145
- MusicFlamingoMultiModalProjector,
146
- MusicFlamingoRotaryEmbedding,
147
- apply_rotary_time_emb,
148
- )
149
-
150
- text_config = {
151
- "model_type": "qwen2",
152
- "intermediate_size": 64,
153
- "initializer_range": 0.02,
154
- "hidden_size": 32,
155
- "max_position_embeddings": 1024,
156
- "num_hidden_layers": 2,
157
- "num_attention_heads": 4,
158
- "num_key_value_heads": 2,
159
- "vocab_size": 128,
160
- "pad_token_id": 1,
161
- "use_mrope": False,
162
- }
163
- audio_config = {
164
- "hidden_size": 16,
165
- "num_attention_heads": 4,
166
- "intermediate_size": 32,
167
- "num_hidden_layers": 2,
168
- "num_mel_bins": 80,
169
- "max_source_positions": 1500,
170
- "dropout": 0.0,
171
- "attention_dropout": 0.0,
172
- "activation_dropout": 0.0,
173
- "encoder_layerdrop": 0.0,
174
- }
175
-
176
- torch.manual_seed(0)
177
- config = MusicFlamingoConfig(
178
- text_config=text_config,
179
- audio_config=audio_config,
180
- audio_token_id=0,
181
- head_dim=8,
182
- rope_parameters={"rope_type": "default", "rope_theta": 2048},
183
- )
184
- hf_model = hf_musicflamingo_modeling.MusicFlamingoForConditionalGeneration(
185
- config
186
- ).eval()
187
-
188
- vllm_encoder = MusicFlamingoEncoder(config.audio_config).eval()
189
- vllm_encoder.load_state_dict(hf_model.audio_tower.state_dict())
190
-
191
- vllm_projector = MusicFlamingoMultiModalProjector(config).eval()
192
- vllm_projector.load_state_dict(hf_model.multi_modal_projector.state_dict())
193
-
194
- vllm_rope = MusicFlamingoRotaryEmbedding(config).eval()
195
- vllm_rope.load_state_dict(hf_model.pos_emb.state_dict(), strict=False)
196
-
197
- input_features = torch.randn(3, 80, 3000)
198
- feature_attention_mask = torch.zeros(3, 3000, dtype=torch.bool)
199
- feature_attention_mask[0, :3000] = True
200
- feature_attention_mask[1, :2500] = True
201
- feature_attention_mask[2, :1500] = True
202
- rote_timestamps = (
203
- torch.arange(750, dtype=torch.float32).unsqueeze(0).repeat(3, 1) * 0.04
204
- )
205
-
206
- hf_output = hf_model.get_audio_features(
207
- input_features,
208
- feature_attention_mask,
209
- rote_timestamps=rote_timestamps,
210
- return_dict=True,
211
- ).pooler_output
212
- vllm_attention_mask = _build_audio_encoder_attention_mask(
213
- feature_attention_mask,
214
- dtype=vllm_encoder.conv1.weight.dtype,
215
- device=vllm_encoder.conv1.weight.device,
216
- )
217
- vllm_hidden_states = vllm_encoder(
218
- input_features,
219
- attention_mask=vllm_attention_mask,
220
- )
221
- cos, sin = vllm_rope(rote_timestamps, seq_len=vllm_hidden_states.shape[-2])
222
- vllm_hidden_states = apply_rotary_time_emb(vllm_hidden_states, cos, sin)
223
- vllm_output, _ = _flatten_valid_audio_embeddings(
224
- vllm_projector(vllm_hidden_states),
225
- feature_attention_mask,
226
- )
227
-
228
- torch.testing.assert_close(vllm_output, hf_output)
tests/models/registry.py
-8
@@ -780,14 +780,6 @@ _MULTIMODAL_EXAMPLE_MODELS = {
780
"vllm": "Needs https://github.com/huggingface/transformers/pull/43538"
781
},
782
),
783
- "MusicFlamingoForConditionalGeneration": _HfExamplesInfo(
784
- "nvidia/music-flamingo-2601-hf",
785
- min_transformers_version="5.5.0",
786
- transformers_version_reason={
787
- "vllm": "Needs https://github.com/huggingface/transformers/pull/43538"
788
- },
789
- ),
790
- "AyaVisionForConditionalGeneration": _HfExamplesInfo("CohereLabs/aya-vision-8b"),
783
"BagelForConditionalGeneration": _HfExamplesInfo("ByteDance-Seed/BAGEL-7B-MoT"),
784
"BeeForConditionalGeneration": _HfExamplesInfo(
785
"Open-Bee/Bee-8B-RL",
vllm/model_executor/models/aya_vision.py
deleted
-445
@@ -1,445 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-# Adapted from https://github.com/huggingface/transformers/tree/main/src/transformers/models/aya_vision
4
-from collections.abc import Iterable, Mapping, Sequence
5
-from typing import Annotated, Literal
6
-
7
-import torch
8
-from torch import nn
9
-from transformers import BatchFeature, GotOcr2ImageProcessor
10
-from transformers.activations import ACT2FN
11
-from transformers.image_processing_utils import get_size_dict
12
-from transformers.models.aya_vision import AyaVisionConfig
13
-from transformers.models.aya_vision.processing_aya_vision import AyaVisionProcessor
14
-from transformers.models.got_ocr2.image_processing_got_ocr2 import (
15
- get_optimal_tiled_canvas,
16
-)
17
-
18
-from vllm.config import VllmConfig
19
-from vllm.config.multimodal import BaseDummyOptions
20
-from vllm.inputs import MultiModalDataDict
21
-from vllm.multimodal import MULTIMODAL_REGISTRY
22
-from vllm.multimodal.inputs import (
23
- MultiModalFieldConfig,
24
- MultiModalKwargsItems,
25
-)
26
-from vllm.multimodal.parse import ImageProcessorItems, ImageSize, MultiModalDataItems
27
-from vllm.multimodal.processing import (
28
- BaseDummyInputsBuilder,
29
- BaseMultiModalProcessor,
30
- BaseProcessingInfo,
31
- PromptReplacement,
32
- PromptUpdate,
33
- PromptUpdateDetails,
34
-)
35
-from vllm.sequence import IntermediateTensors
36
-from vllm.utils.tensor_schema import TensorSchema, TensorShape
37
-
38
-from .interfaces import MultiModalEmbeddings, SupportsMultiModal, SupportsPP
39
-from .siglip import SiglipVisionModel
40
-from .utils import (
41
- AutoWeightsLoader,
42
- WeightsMapper,
43
- get_layer_index,
44
- init_vllm_registered_model,
45
- maybe_prefix,
46
-)
47
-
48
-
49
-class AyaVisionImagePixelInputs(TensorSchema):
50
- """
51
- Dimensions:
52
- - np: The total number of patches over each image over each prompt in
53
- the batch
54
- - c: Number of channels
55
- - h: Height of each image patch
56
- - w: Width of each image patch
57
- - bn: Batch size * number of images
58
- """
59
-
60
- type: Literal["pixel_values"]
61
-
62
- pixel_values: Annotated[
63
- torch.Tensor,
64
- TensorShape("np", 3, "h", "w"),
65
- ]
66
-
67
- num_patches: Annotated[
68
- torch.Tensor,
69
- TensorShape("bn"),
70
- ]
71
-
72
-
73
-class AyaVisionMultiModalProjector(nn.Module):
74
- def __init__(self, config: AyaVisionConfig):
75
- super().__init__()
76
- self.config = config
77
- self.downsample_factor = config.downsample_factor
78
- self.alignment_intermediate_size = getattr(
79
- config, "alignment_intermediate_size", config.text_config.hidden_size
80
- )
81
- self.layernorm = nn.LayerNorm(
82
- config.vision_config.hidden_size * (config.downsample_factor**2),
83
- eps=config.adapter_layer_norm_eps,
84
- )
85
-
86
- self.linear_1 = nn.Linear(
87
- config.vision_config.hidden_size * (config.downsample_factor**2),
88
- self.alignment_intermediate_size,
89
- bias=True,
90
- )
91
-
92
- self.act = ACT2FN["silu"] # SwiGLU uses SiLU activation
93
- # For SwiGLU, project down to half size since we split intermediate dim
94
- self.linear_2 = nn.Linear(
95
- self.alignment_intermediate_size // 2,
96
- config.text_config.hidden_size,
97
- bias=True,
98
- )
99
-
100
- def forward(self, image_features: torch.Tensor) -> torch.Tensor:
101
- image_features = self.pixel_shuffle(image_features)
102
- image_features = self.layernorm(image_features)
103
- hidden_states = self.linear_1(image_features)
104
-
105
- # Split along last dimension and apply SwiGLU
106
- x, gate = hidden_states.chunk(2, dim=-1)
107
- hidden_states = self.act(gate) * x
108
-
109
- hidden_states = self.linear_2(hidden_states)
110
- return hidden_states
111
-
112
- def pixel_shuffle(self, image_features: torch.Tensor) -> torch.Tensor: # B, S, D
113
- batch_size, seq_length, _ = image_features.shape
114
- height = width = int(seq_length**0.5)
115
- image_features = image_features.reshape(
116
- image_features.shape[0], width, height, -1
117
- )
118
- channels = image_features.shape[-1]
119
- image_features = image_features.reshape(
120
- batch_size,
121
- width,
122
- int(height / self.downsample_factor),
123
- int(channels * self.downsample_factor),
124
- )
125
- image_features = image_features.permute(0, 2, 1, 3)
126
- image_features = image_features.reshape(
127
- batch_size,
128
- int(height / self.downsample_factor),
129
- int(width / self.downsample_factor),
130
- -1,
131
- )
132
- image_features = image_features.permute(0, 2, 1, 3)
133
- return image_features
134
-
135
-
136
-class AyaVisionProcessingInfo(BaseProcessingInfo):
137
- def get_hf_config(self) -> AyaVisionConfig:
138
- return self.ctx.get_hf_config(AyaVisionConfig)
139
-
140
- def get_hf_processor(self, **kwargs: object) -> AyaVisionProcessor:
141
- return self.ctx.get_hf_processor(AyaVisionProcessor, **kwargs)
142
-
143
- def get_image_processor(self, **kwargs: object) -> GotOcr2ImageProcessor:
144
- return self.get_hf_processor(**kwargs).image_processor
145
-
146
- def get_supported_mm_limits(self) -> Mapping[str, int | None]:
147
- return {"image": None}
148
-
149
- def get_image_size_with_most_features(self) -> ImageSize:
150
- image_processor = self.get_image_processor()
151
- height = image_processor.size["height"]
152
- width = image_processor.size["width"]
153
- max_patches = image_processor.max_patches
154
- return ImageSize(height=height * max_patches, width=width * max_patches)
155
-
156
- def get_num_patches(
157
- self,
158
- *,
159
- image_width: int,
160
- image_height: int,
161
- size: dict,
162
- min_patches: int,
163
- max_patches: int,
164
- ) -> int:
165
- """
166
- Calculate the number of patches needed for a given image based on size
167
- constraints. This method replicates and adjusts the logic from:
168
- transformers/models/got_ocr2/image_processing_got_ocr2
169
- """
170
- size = get_size_dict(size, default_to_square=False)
171
- num_columns, num_rows = get_optimal_tiled_canvas(
172
- (image_height, image_width),
173
- (size["height"], size["width"]),
174
- min_patches,
175
- max_patches,
176
- )
177
- num_blocks = num_columns * num_rows
178
- return num_blocks if num_blocks == 1 else num_blocks + 1
179
-
180
-
181
-class AyaVisionDummyInputsBuilder(BaseDummyInputsBuilder[AyaVisionProcessingInfo]):
182
- def get_dummy_text(self, mm_counts: Mapping[str, int]) -> str:
183
- num_images = mm_counts.get("image", 0)
184
-
185
- processor = self.info.get_hf_processor()
186
- image_token = processor.image_token
187
-
188
- return image_token * num_images
189
-
190
- def get_dummy_mm_data(
191
- self,
192
- seq_len: int,
193
- mm_counts: Mapping[str, int],
194
- mm_options: Mapping[str, BaseDummyOptions],
195
- ) -> MultiModalDataDict:
196
- num_images = mm_counts.get("image", 0)
197
- image_size = self.info.get_image_size_with_most_features()
198
-
199
- image_overrides = mm_options.get("image")
200
-
201
- return {
202
- "image": self._get_dummy_images(
203
- width=image_size.width,
204
- height=image_size.height,
205
- num_images=num_images,
206
- overrides=image_overrides,
207
- )
208
- }
209
-
210
-
211
-class AyaVisionMultiModalProcessor(BaseMultiModalProcessor[AyaVisionProcessingInfo]):
212
- def _call_hf_processor(
213
- self,
214
- prompt: str,
215
- mm_data: Mapping[str, object],
216
- mm_kwargs: Mapping[str, object],
217
- tok_kwargs: Mapping[str, object],
218
- ) -> BatchFeature:
219
- processed_outputs = super()._call_hf_processor(
220
- prompt,
221
- mm_data,
222
- mm_kwargs,
223
- tok_kwargs,
224
- )
225
- hf_processor = self.info.get_hf_processor(**mm_kwargs)
226
- image_processor = hf_processor.image_processor
227
-
228
- # HF processor pops the `num_patches` kwarg, which is needed by vLLM
229
- if (images := mm_data.get("images")) is not None:
230
- mm_items = self.info.parse_mm_data({"image": images}, validate=False)
231
- parsed_images = mm_items.get_items("image", ImageProcessorItems)
232
- image_sizes = [
233
- parsed_images.get_image_size(i) for i in range(len(parsed_images))
234
- ]
235
-
236
- num_patches = [
237
- self.info.get_num_patches(
238
- image_width=image_size.width,
239
- image_height=image_size.height,
240
- size=image_processor.size,
241
- min_patches=image_processor.min_patches,
242
- max_patches=image_processor.max_patches,
243
- )
244
- for image_size in image_sizes
245
- ]
246
- processed_outputs["num_patches"] = torch.tensor(num_patches)
247
-
248
- return processed_outputs
249
-
250
- def _get_mm_fields_config(
251
- self,
252
- hf_inputs: BatchFeature,
253
- hf_processor_mm_kwargs: Mapping[str, object],
254
- ) -> Mapping[str, MultiModalFieldConfig]:
255
- num_patches = hf_inputs.get("num_patches", torch.empty(0))
256
- return dict(
257
- pixel_values=MultiModalFieldConfig.flat_from_sizes("image", num_patches),
258
- num_patches=MultiModalFieldConfig.batched("image"),
259
- image_embeds=MultiModalFieldConfig.batched("image"),
260
- )
261
-
262
- def _get_prompt_updates(
263
- self,
264
- mm_items: MultiModalDataItems,
265
- hf_processor_mm_kwargs: Mapping[str, object],
266
- out_mm_kwargs: MultiModalKwargsItems,
267
- ) -> Sequence[PromptUpdate]:
268
- hf_processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
269
- image_token = hf_processor.image_token
270
- img_patch_token = hf_processor.img_patch_token
271
- image_processor = hf_processor.image_processor
272
-
273
- def get_replacement(item_idx: int):
274
- images = mm_items.get_items("image", ImageProcessorItems)
275
- image_size: ImageSize = images.get_image_size(item_idx)
276
- num_patches = self.info.get_num_patches(
277
- image_width=image_size.width,
278
- image_height=image_size.height,
279
- size=image_processor.size,
280
- min_patches=image_processor.min_patches,
281
- max_patches=image_processor.max_patches,
282
- )
283
- repl = hf_processor._prompt_split_image(num_patches=num_patches)
284
-
285
- return PromptUpdateDetails.select_text(repl, img_patch_token)
286
-
287
- return [
288
- PromptReplacement(
289
- modality="image",
290
- target=image_token,
291
- replacement=get_replacement,
292
- )
293
- ]
294
-
295
-
296
-def _get_num_hidden_layers(hf_config: AyaVisionConfig) -> int:
297
- feature_layers = hf_config.vision_feature_layer
298
- num_hidden_layers = hf_config.vision_config.num_hidden_layers
299
- # If we have one feature layer, initialize up to that layer
300
- if isinstance(feature_layers, int):
301
- return get_layer_index(feature_layers, num_hidden_layers)
302
- # If we have multiple feature layers, initialize up to the deepest m
303
- elif isinstance(feature_layers, (list, tuple)):
304
- return max(get_layer_index(idx, num_hidden_layers) for idx in feature_layers)
305
- raise TypeError(
306
- f"vision_layer_feature type: {type(feature_layers)} is not supported"
307
- )
308
-
309
-
310
-@MULTIMODAL_REGISTRY.register_processor(
311
- AyaVisionMultiModalProcessor,
312
- info=AyaVisionProcessingInfo,
313
- dummy_inputs=AyaVisionDummyInputsBuilder,
314
-)
315
-class AyaVisionForConditionalGeneration(nn.Module, SupportsMultiModal, SupportsPP):
316
- hf_to_vllm_mapper = WeightsMapper(
317
- orig_to_new_prefix={
318
- # mapping for new names in checkpoint saved after transformers v4.52
319
- "model.language_model.": "language_model.model.",
320
- "model.vision_tower.": "vision_tower.",
321
- "model.multi_modal_projector.": "multi_modal_projector.",
322
- "lm_head.": "language_model.lm_head.",
323
- }
324
- )
325
-
326
- @classmethod
327
- def get_placeholder_str(cls, modality: str, i: int) -> str | None:
328
- if modality.startswith("image"):
329
- return "<image>"
330
-
331
- raise ValueError("Only image modality is supported")
332
-
333
- def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
334
- super().__init__()
335
- config: AyaVisionConfig = vllm_config.model_config.hf_config
336
- quant_config = vllm_config.quant_config
337
- multimodal_config = vllm_config.model_config.multimodal_config
338
- num_hidden_layers = _get_num_hidden_layers(config)
339
- self.config = config
340
- self.quant_config = quant_config
341
- self.multimodal_config = multimodal_config
342
-
343
- with self._mark_tower_model(vllm_config, "image"):
344
- self.vision_tower = SiglipVisionModel(
345
- config.vision_config,
346
- quant_config,
347
- num_hidden_layers_override=num_hidden_layers,
348
- prefix=maybe_prefix(prefix, "vision_model"),
349
- )
350
- self.multi_modal_projector = AyaVisionMultiModalProjector(config)
351
-
352
- with self._mark_language_model(vllm_config):
353
- self.language_model = init_vllm_registered_model(
354
- vllm_config=vllm_config,
355
- hf_config=config.text_config,
356
- prefix=maybe_prefix(prefix, "model"),
357
- # Cohere2ForCausalLM and CohereForCausalLM are the same on vllm
358
- architectures=["Cohere2ForCausalLM"],
359
- )
360
-
361
- self.make_empty_intermediate_tensors = (
362
- self.language_model.make_empty_intermediate_tensors
363
- )
364
-
365
- @property
366
- def dtype(self):
367
- return next(self.parameters()).dtype
368
-
369
- def load_weights(self, weights: Iterable[tuple[str, torch.Tensor]]) -> set[str]:
370
- loader = AutoWeightsLoader(self)
371
- return loader.load_weights(weights, mapper=self.hf_to_vllm_mapper)
372
-
373
- def _image_pixels_to_features(
374
- self,
375
- vision_tower: SiglipVisionModel,
376
- pixel_values: torch.Tensor,
377
- ) -> torch.Tensor | tuple[torch.Tensor, ...]:
378
- return vision_tower(
379
- pixel_values.to(dtype=vision_tower.dtype),
380
- feature_select_strategy=self.config.vision_feature_select_strategy,
381
- )
382
-
383
- def _process_image_input(
384
- self, image_input: AyaVisionImagePixelInputs, **kwargs
385
- ) -> list[torch.Tensor]:
386
- pixel_values = image_input["pixel_values"]
387
- num_patches = image_input["num_patches"]
388
- image_features = self._image_pixels_to_features(
389
- self.vision_tower, pixel_values=pixel_values
390
- )
391
- image_embeds = self.multi_modal_projector(image_features)
392
- return [e.flatten(0, 2) for e in image_embeds.split(num_patches.tolist())]
393
-
394
- def _parse_and_validate_image_input(
395
- self, **kwargs: object
396
- ) -> AyaVisionImagePixelInputs | None:
397
- pixel_values = kwargs.pop("pixel_values", None)
398
- num_patches = kwargs.pop("num_patches", None)
399
- image_embeds = kwargs.pop("image_embeds", None)
400
- assert image_embeds is None, "Aya Vision does not support image_embeds."
401
-
402
- if pixel_values is None:
403
- return None
404
-
405
- return AyaVisionImagePixelInputs(
406
- type="pixel_values",
407
- pixel_values=pixel_values,
408
- num_patches=num_patches,
409
- resolve_bindings={
410
- "h": self.config.vision_config.image_size,
411
- "w": self.config.vision_config.image_size,
412
- },
413
- )
414
-
415
- def embed_multimodal(self, **kwargs: object) -> MultiModalEmbeddings:
416
- image_input = self._parse_and_validate_image_input(**kwargs)
417
- if image_input is None:
418
- return []
419
-
420
- return self._process_image_input(image_input, **kwargs)
421
-
422
- def forward(
423
- self,
424
- input_ids: torch.Tensor | None,
425
- positions: torch.Tensor,
426
- intermediate_tensors: IntermediateTensors | None = None,
427
- inputs_embeds: torch.Tensor | None = None,
428
- **kwargs: object,
429
- ) -> torch.Tensor | IntermediateTensors:
430
- if intermediate_tensors is not None:
431
- inputs_embeds = None
432
-
433
- hidden_states = self.language_model.model(
434
- input_ids=input_ids,
435
- positions=positions,
436
- intermediate_tensors=intermediate_tensors,
437
- inputs_embeds=inputs_embeds,
438
- )
439
- return hidden_states
440
-
441
- def compute_logits(
442
- self,
443
- hidden_states: torch.Tensor,
444
- ) -> torch.Tensor | None:
445
- return self.language_model.compute_logits(hidden_states)
vllm/model_executor/models/musicflamingo.py
deleted
-449
@@ -1,449 +0,0 @@
1
-# SPDX-License-Identifier: Apache-2.0
2
-# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
-
4
-# Copyright 2026 The vLLM team.
5
-# Copyright 2026 NVIDIA CORPORATION and the HuggingFace Inc. team. All rights
6
-# reserved.
7
-#
8
-# Licensed under the Apache License, Version 2.0 (the "License");
9
-# you may not use this file except in compliance with the License.
10
-# You may obtain a copy of the License at
11
-#
12
-# http://www.apache.org/licenses/LICENSE-2.0
13
-#
14
-# Unless required by applicable law or agreed to in writing, software
15
-# distributed under the License is distributed on an "AS IS" BASIS,
16
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
-# See the License for the specific language governing permissions and
18
-# limitations under the License.
19
-
20
-from collections.abc import Callable, Mapping, Sequence
21
-from math import pi
22
-from typing import Annotated, Any, Optional, TypeAlias
23
-
24
-import torch
25
-from torch import Tensor, broadcast_tensors, nn
26
-from transformers import BatchFeature
27
-from transformers.modeling_rope_utils import ROPE_INIT_FUNCTIONS
28
-from transformers.models.musicflamingo import (
29
- MusicFlamingoConfig,
30
- MusicFlamingoProcessor,
31
-)
32
-
33
-from vllm.config import VllmConfig
34
-from vllm.config.multimodal import BaseDummyOptions
35
-from vllm.inputs import MultiModalDataDict
36
-from vllm.multimodal import MULTIMODAL_REGISTRY
37
-from vllm.multimodal.inputs import (
38
- MultiModalFieldConfig,
39
- MultiModalKwargsItems,
40
-)
41
-from vllm.multimodal.parse import (
42
- DictEmbeddingItems,
43
- ModalityData,
44
- ModalityDataItems,
45
- MultiModalDataItems,
46
- MultiModalDataParser,
47
-)
48
-from vllm.multimodal.processing import (
49
- PromptReplacement,
50
- PromptUpdate,
51
- PromptUpdateDetails,
52
-)
53
-from vllm.utils.tensor_schema import TensorShape
54
-
55
-from .audioflamingo3 import (
56
- AudioFlamingo3DummyInputsBuilder,
57
- AudioFlamingo3EmbeddingInputs,
58
- AudioFlamingo3Encoder,
59
- AudioFlamingo3FeatureInputs,
60
- AudioFlamingo3ForConditionalGeneration,
61
- AudioFlamingo3MultiModalDataParser,
62
- AudioFlamingo3MultiModalProcessor,
63
- AudioFlamingo3MultiModalProjector,
64
- AudioFlamingo3ProcessingInfo,
65
- _audioflamingo3_field_config,
66
- _count_audio_tokens_from_mask,
67
-)
68
-
69
-
70
-def rotate_half(x):
71
- x = x.reshape(*x.shape[:-1], -1, 2)
72
- x1, x2 = x.unbind(dim=-1)
73
- x = torch.stack((-x2, x1), dim=-1)
74
- return x.flatten(-2)
75
-
76
-
77
-def apply_rotary_time_emb(hidden_states, cos, sin):
78
- original_dtype = hidden_states.dtype
79
- hidden_states = hidden_states.to(torch.float64)
80
- cos = cos.to(hidden_states)
81
- sin = sin.to(hidden_states)
82
- rot_dim = cos.shape[-1]
83
- if rot_dim > hidden_states.shape[-1]:
84
- raise ValueError(
85
- f"feature dimension {hidden_states.shape[-1]} is not of "
86
- f"sufficient size to rotate in all the positions {rot_dim}"
87
- )
88
-
89
- rotated = hidden_states[..., :rot_dim]
90
- passthrough = hidden_states[..., rot_dim:]
91
- rotated = (rotated * cos) + (rotate_half(rotated) * sin)
92
- return torch.cat((rotated, passthrough), dim=-1).to(original_dtype)
93
-
94
-
95
-class MusicFlamingoRotaryEmbedding(nn.Module):
96
- inv_freq: torch.Tensor
97
-
98
- def __init__(self, config: MusicFlamingoConfig, device=None):
99
- super().__init__()
100
- self.max_seq_len_cached = config.max_position_embeddings
101
- self.original_max_seq_len = config.max_position_embeddings
102
-
103
- self.config = config
104
- self.rope_type = self.config.rope_parameters["rope_type"]
105
- rope_init_fn: Callable = self.compute_default_rope_parameters
106
- if self.rope_type != "default":
107
- rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
108
- inv_freq, self.attention_scaling = rope_init_fn(self.config, device)
109
-
110
- self.register_buffer("inv_freq", inv_freq, persistent=False)
111
- self.register_buffer("original_inv_freq", inv_freq.clone(), persistent=False)
112
- position_angles = self._compute_position_angles(self.inv_freq)
113
- self.register_buffer("position_angles", position_angles, persistent=False)
114
-
115
- @staticmethod
116
- def compute_default_rope_parameters(
117
- config: MusicFlamingoConfig | None = None,
118
- device: Optional["torch.device"] = None,
119
- seq_len: int | None = None,
120
- ) -> tuple["torch.Tensor", float]:
121
- del seq_len
122
- base = config.rope_parameters["rope_theta"]
123
- partial_rotary_factor = config.rope_parameters.get("partial_rotary_factor", 1.0)
124
- head_dim = getattr(config, "head_dim", None) or (
125
- config.hidden_size // config.num_attention_heads
126
- )
127
- dim = int(head_dim * partial_rotary_factor)
128
- attention_factor = 1.0
129
-
130
- inv_freq = 1.0 / (
131
- base
132
- ** (
133
- torch.arange(0, dim, 2, dtype=torch.int64).to(
134
- device=device,
135
- dtype=torch.float,
136
- )
137
- / dim
138
- )
139
- )
140
- return inv_freq, attention_factor
141
-
142
- def _compute_position_angles(self, inv_freq):
143
- positions = torch.arange(
144
- int(self.max_seq_len_cached),
145
- device=inv_freq.device,
146
- dtype=inv_freq.dtype,
147
- )
148
- positions = positions / self.max_seq_len_cached * (2 * pi)
149
- position_angles = positions.unsqueeze(-1) * inv_freq
150
- position_angles = torch.repeat_interleave(position_angles, 2, dim=-1)
151
- return position_angles.to(dtype=inv_freq.dtype)
152
-
153
- def _restore_fp32_rope_buffers(self) -> None:
154
- rope_init_fn: Callable = self.compute_default_rope_parameters
155
- if self.rope_type != "default":
156
- rope_init_fn = ROPE_INIT_FUNCTIONS[self.rope_type]
157
- inv_freq, self.attention_scaling = rope_init_fn(
158
- self.config, self.inv_freq.device
159
- )
160
-
161
- self.inv_freq = inv_freq
162
- self.original_inv_freq = inv_freq.clone()
163
- self.position_angles = self._compute_position_angles(inv_freq)
164
-
165
- def _apply(self, fn):
166
- super()._apply(fn)
167
- self._restore_fp32_rope_buffers()
168
- return self
169
-
170
- @torch.no_grad()
171
- def forward(self, timestamps: Tensor, seq_len: int) -> tuple[Tensor, Tensor]:
172
- window_starts = timestamps[:, 0].to(
173
- device=self.inv_freq.device,
174
- dtype=self.inv_freq.dtype,
175
- )
176
- window_duration = self.config.audio_frame_step * 4 * seq_len
177
- window_positions = (
178
- torch.round(window_starts / window_duration) / self.max_seq_len_cached
179
- )
180
- window_freqs = window_positions.unsqueeze(-1) * self.inv_freq
181
- window_freqs = torch.repeat_interleave(window_freqs, 2, dim=-1)
182
-
183
- window_freqs = window_freqs[:, None, :]
184
- time_freqs = self.position_angles[:seq_len][None, :, :]
185
- window_freqs, time_freqs = broadcast_tensors(window_freqs, time_freqs)
186
- freqs = torch.cat((window_freqs, time_freqs), dim=-1)
187
- angle = (-timestamps * 2 * pi).to(freqs)
188
- freqs = freqs * angle.unsqueeze(-1)
189
- return freqs.cos(), freqs.sin()
190
-
191
-
192
-class MusicFlamingoFeatureInputs(AudioFlamingo3FeatureInputs):
193
- rote_timestamps: Annotated[
194
- torch.Tensor | None,
195
- TensorShape(
196
- "num_chunks",
197
- "num_audio_time_steps",
198
- dynamic_dims={"num_audio_time_steps"},
199
- ),
200
- ]
201
-
202
-
203
-MusicFlamingoEmbeddingInputs = AudioFlamingo3EmbeddingInputs
204
-
205
-MusicFlamingoInputs: TypeAlias = (
206
- MusicFlamingoFeatureInputs | MusicFlamingoEmbeddingInputs
207
-)
208
-
209
-
210
-class MusicFlamingoEncoder(AudioFlamingo3Encoder):
211
- pass
212
-
213
-
214
-class MusicFlamingoMultiModalProjector(AudioFlamingo3MultiModalProjector):
215
- pass
216
-
217
-
218
-class MusicFlamingoProcessingInfo(AudioFlamingo3ProcessingInfo):
219
- def get_hf_config(self) -> MusicFlamingoConfig:
220
- return self.ctx.get_hf_config(MusicFlamingoConfig)
221
-
222
- def get_hf_processor(self, **kwargs: object) -> MusicFlamingoProcessor:
223
- return self.ctx.get_hf_processor(MusicFlamingoProcessor, **kwargs)
224
-
225
- def get_data_parser(self) -> MultiModalDataParser:
226
- feature_extractor = self.get_feature_extractor()
227
- return MusicFlamingoMultiModalDataParser(
228
- target_sr=feature_extractor.sampling_rate,
229
- audio_resample_method="soxr",
230
- expected_hidden_size=self._get_expected_hidden_size(),
231
- )
232
-
233
- def get_supported_mm_limits(self) -> Mapping[str, int | None]:
234
- return {"audio": 1}
235
-
236
-
237
-class MusicFlamingoDummyInputsBuilder(AudioFlamingo3DummyInputsBuilder):
238
- def get_dummy_text(self, mm_counts: Mapping[str, int]) -> str:
239
- num_audios = mm_counts.get("audio", 0)
240
- hf_processor = self.info.get_hf_processor()
241
- return hf_processor.audio_token * num_audios
242
-
243
- def get_dummy_mm_data(
244
- self,
245
- seq_len: int,
246
- mm_counts: Mapping[str, int],
247
- mm_options: Mapping[str, BaseDummyOptions],
248
- ) -> MultiModalDataDict:
249
- hf_processor = self.info.get_hf_processor()
250
- feature_extractor = self.info.get_feature_extractor()
251
- sampling_rate = feature_extractor.sampling_rate
252
- audio_len = int(hf_processor.max_audio_len * sampling_rate)
253
- num_audios = mm_counts.get("audio", 0)
254
- audio_overrides = mm_options.get("audio")
255
-
256
- return {
257
- "audio": self._get_dummy_audios(
258
- length=audio_len,
259
- num_audios=num_audios,
260
- overrides=audio_overrides,
261
- )
262
- }
263
-
264
-
265
-def _musicflamingo_field_config(hf_inputs: Mapping[str, torch.Tensor]):
266
- fields = dict(_audioflamingo3_field_config(hf_inputs))
267
- chunk_counts = hf_inputs.get("chunk_counts")
268
- if chunk_counts is not None:
269
- fields["rote_timestamps"] = MultiModalFieldConfig.flat_from_sizes(
270
- "audio", chunk_counts, dim=0
271
- )
272
- else:
273
- fields["rote_timestamps"] = MultiModalFieldConfig.batched("audio")
274
- return fields
275
-
276
-
277
-class MusicFlamingoMultiModalDataParser(AudioFlamingo3MultiModalDataParser):
278
- def _parse_audio_data(
279
- self,
280
- data: dict[str, torch.Tensor] | ModalityData[Any],
281
- ) -> ModalityDataItems[Any, Any] | None:
282
- if isinstance(data, dict):
283
- return DictEmbeddingItems(
284
- data,
285
- modality="audio",
286
- required_fields={"audio_embeds"},
287
- fields_factory=_musicflamingo_field_config,
288
- )
289
- return super()._parse_audio_data(data)
290
-
291
-
292
-class MusicFlamingoMultiModalProcessor(AudioFlamingo3MultiModalProcessor):
293
- def _get_mm_fields_config(
294
- self,
295
- hf_inputs: BatchFeature,
296
- hf_processor_mm_kwargs: Mapping[str, object],
297
- ) -> Mapping[str, MultiModalFieldConfig]:
298
- return _musicflamingo_field_config(hf_inputs)
299
-
300
- def _get_prompt_updates(
301
- self,
302
- mm_items: MultiModalDataItems,
303
- hf_processor_mm_kwargs: Mapping[str, object],
304
- out_mm_kwargs: MultiModalKwargsItems,
305
- ) -> Sequence[PromptUpdate]:
306
- processor = self.info.get_hf_processor(**hf_processor_mm_kwargs)
307
- tokenizer = self.info.get_tokenizer()
308
- vocab = tokenizer.get_vocab()
309
-
310
- audio_token = processor.audio_token
311
- audio_token_id = vocab.get(audio_token, processor.audio_token_id)
312
-
313
- audio_bos_token = processor.audio_bos_token
314
- audio_bos_token_id = vocab.get(audio_bos_token, processor.audio_bos_token_id)
315
-
316
- audio_eos_token = processor.audio_eos_token
317
- audio_eos_token_id = vocab.get(audio_eos_token, processor.audio_eos_token_id)
318
-
319
- out_mm_data = out_mm_kwargs.get_data()
320
- feature_attention_mask = out_mm_data.get("feature_attention_mask")
321
- chunk_counts = out_mm_data.get("chunk_counts")
322
-
323
- def get_replacement_musicflamingo(item_idx: int):
324
- if feature_attention_mask is not None:
325
- num_features = _count_audio_tokens_from_mask(
326
- feature_attention_mask,
327
- chunk_counts,
328
- item_idx,
329
- )
330
- else:
331
- audio_embeds = out_mm_data["audio_embeds"][item_idx]
332
- num_features = audio_embeds.shape[0]
333
-
334
- if num_features == 0:
335
- raise ValueError("Audio is too short")
336
-
337
- full_tokens = [
338
- audio_bos_token_id,
339
- *([audio_token_id] * int(num_features)),
340
- audio_eos_token_id,
341
- ]
342
-
343
- return PromptUpdateDetails.select_token_id(
344
- full_tokens,
345
- embed_token_id=audio_token_id,
346
- )
347
-
348
- return [
349
- PromptReplacement(
350
- modality="audio",
351
- target=audio_token,
352
- replacement=get_replacement_musicflamingo,
353
- )
354
- ]
355
-
356
-
357
-@MULTIMODAL_REGISTRY.register_processor(
358
- MusicFlamingoMultiModalProcessor,
359
- info=MusicFlamingoProcessingInfo,
360
- dummy_inputs=MusicFlamingoDummyInputsBuilder,
361
-)
362
-class MusicFlamingoForConditionalGeneration(AudioFlamingo3ForConditionalGeneration):
363
- """vLLM MusicFlamingo model aligned with HF modular_musicflamingo."""
364
-
365
- def __init__(self, *, vllm_config: VllmConfig, prefix: str = ""):
366
- super().__init__(vllm_config=vllm_config, prefix=prefix)
367
- self.audio_tower = MusicFlamingoEncoder(self.config.audio_config)
368
- self.multi_modal_projector = MusicFlamingoMultiModalProjector(self.config)
369
- self.pos_emb = MusicFlamingoRotaryEmbedding(self.config)
370
-
371
- def _parse_and_validate_audio_input(
372
- self, **kwargs: object
373
- ) -> MusicFlamingoInputs | None:
374
- rote_timestamps = kwargs.pop("rote_timestamps", None)
375
- audio_input = super()._parse_and_validate_audio_input(**kwargs)
376
- if audio_input is None or audio_input["type"] == "audio_embeds":
377
- return audio_input
378
-
379
- return MusicFlamingoFeatureInputs(
380
- type="audio_features",
381
- input_features=audio_input["input_features"],
382
- feature_attention_mask=audio_input["feature_attention_mask"],
383
- chunk_counts=audio_input["chunk_counts"],
384
- rote_timestamps=rote_timestamps,
385
- )
386
-
387
- def _build_audio_timestamps(
388
- self,
389
- chunk_counts: list[int],
390
- seq_len: int,
391
- device: torch.device,
392
- ) -> torch.Tensor:
393
- audio_embed_frame_step = self.config.audio_frame_step * 4
394
- frame_offsets = (
395
- torch.arange(seq_len, device=device, dtype=torch.float32)
396
- * audio_embed_frame_step
397
- )
398
-
399
- if not chunk_counts:
400
- return frame_offsets.new_empty((0, seq_len))
401
-
402
- window_indices = torch.cat(
403
- [
404
- torch.arange(count, device=device, dtype=torch.float32)
405
- for count in chunk_counts
406
- ]
407
- )
408
- return (
409
- window_indices.unsqueeze(1) * seq_len * audio_embed_frame_step
410
- + frame_offsets
411
- )
412
-
413
- def _process_audio_input(
414
- self, audio_input: MusicFlamingoInputs
415
- ) -> torch.Tensor | tuple[torch.Tensor, ...]:
416
- if audio_input["type"] == "audio_embeds":
417
- return super()._process_audio_input(audio_input)
418
-
419
- rote_timestamps = audio_input["rote_timestamps"]
420
- (
421
- input_features,
422
- feature_attention_mask,
423
- chunk_counts,
424
- ) = self._normalize_audio_feature_inputs(audio_input)
425
- hidden_states = self._encode_audio_features(
426
- input_features,
427
- feature_attention_mask,
428
- )
429
- if rote_timestamps is None:
430
- rote_timestamps = self._build_audio_timestamps(
431
- chunk_counts,
432
- seq_len=hidden_states.shape[-2],
433
- device=hidden_states.device,
434
- )
435
- elif isinstance(rote_timestamps, list):
436
- rote_timestamps = torch.cat(rote_timestamps, dim=0)
437
-
438
- cos, sin = self.pos_emb(
439
- rote_timestamps.to(hidden_states.device),
440
- seq_len=hidden_states.shape[-2],
441
- )
442
- hidden_states = apply_rotary_time_emb(hidden_states, cos, sin)
443
- audio_features = self.multi_modal_projector(hidden_states)
444
-
445
- return self._group_audio_embeddings(
446
- audio_features,
447
- feature_attention_mask,
448
- chunk_counts,
449
- )
vllm/model_executor/models/registry.py
+2
-8
@@ -337,14 +337,6 @@ _MULTIMODAL_MODELS = {
337
"audioflamingo3",
338
"AudioFlamingo3ForConditionalGeneration",
339
),
340
- "MusicFlamingoForConditionalGeneration": (
341
- "musicflamingo",
342
- "MusicFlamingoForConditionalGeneration",
343
- ),
344
- "AyaVisionForConditionalGeneration": (
345
- "aya_vision",
346
- "AyaVisionForConditionalGeneration",
347
- ),
340
"BagelForConditionalGeneration": ("bagel", "BagelForConditionalGeneration"),
341
"BeeForConditionalGeneration": ("bee", "BeeForConditionalGeneration"),
342
"Blip2ForConditionalGeneration": ("blip2", "Blip2ForConditionalGeneration"),
@@ -733,6 +725,8 @@ _PREVIOUSLY_SUPPORTED_MODELS = {
725
"TarsierForConditionalGeneration": "0.24.0",
726
"Tarsier2ForConditionalGeneration": "0.23.0", # last version with Transformers v4
727
"MantisForConditionalGeneration": "0.24.0",
728
+ "MusicFlamingoForConditionalGeneration": "0.24.0",
729
+ "AyaVisionForConditionalGeneration": "0.24.0",
730
}
731
732
_OOT_SUPPORTED_MODELS = {
vllm/transformers_utils/model_arch_config_convertor.py
+1
-1
@@ -345,7 +345,7 @@ class ModelArchConfigConvertorBase:
345
max_len_key = key
346
derived_max_model_len = min(derived_max_model_len, max_len)
347
348
- # For Command-R / Cohere, Cohere2 / Aya Vision models
348
+ # For Command-R / Cohere, Cohere2 models
349
if tmp_max_len := getattr(self.hf_text_config, "model_max_length", None):
350
max_len_key = "model_max_length"
351
derived_max_model_len = tmp_max_len