A high-throughput and memory-efficient inference and serving engine for LLMs
Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git
Synced Nov 2, 07:15 UTC
[BugFix] Fix TypeError in MiniCPM-O audio feature unpadding (#38053)
Signed-off-by: Krishna Chaitanya Balusu <krishnabkc15@gmail.com> Signed-off-by: wjinxu <1299461899@qq.com> Signed-off-by: Kc Balusu <kcbalusu@users.noreply.github.com> Co-authored-by: wjinxu <1299461899@qq.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Cyrus Leung <tlleungac@connect.ust.hk> Co-authored-by: Kc Balusu <kcbalusu@users.noreply.github.com>
Krishna Chaitanya committed
Jun 1, 2026 at 19:57 UTC
279d25f5cbc8d0182672556aa66aae9b09301a23
1 file changed
+71
-4
vllm/model_executor/models/minicpmo.py
+71
-4
@@ -173,9 +173,64 @@ MiniCPMOAudioInputs: TypeAlias = (
173
174
175
def _minicpmo_field_config(hf_inputs: Mapping[str, torch.Tensor]):
176
+ audio_features = hf_inputs.get("audio_features")
177
+ audio_feature_lens = hf_inputs.get("audio_feature_lens")
178
+
179
+ # For multi-chunk audio (>30s), audio_features has one item per chunk
180
+ # (total_chunks) while audio_feature_lens has one item per audio (N).
181
+ # Use flat to group audio_features by audio so both fields
182
+ # share the same batch size (N).
183
+ audio_features_cfg = MultiModalFieldConfig.batched("audio")
184
+
185
+ if audio_features is not None and audio_feature_lens is not None:
186
+ num_features = (
187
+ len(audio_features)
188
+ if isinstance(audio_features, (list, tuple))
189
+ else audio_features.shape[0]
190
+ )
191
+ num_audios = (
192
+ len(audio_feature_lens)
193
+ if isinstance(audio_feature_lens, (list, tuple))
194
+ else audio_feature_lens.shape[0]
195
+ )
196
+
197
+ if num_features > num_audios:
198
+ # Compute the number of chunks belonging to each audio
199
+ chunks_per_audio: list[int] = []
200
+ for lens in audio_feature_lens:
201
+ if isinstance(lens, torch.Tensor):
202
+ chunks_per_audio.append(lens.numel())
203
+ else:
204
+ chunks_per_audio.append(1)
205
+
206
+ # When audio_feature_lens is padded (e.g. from batched HF
207
+ # processor output), numel() over-counts. Fall back to
208
+ # counting non-zero entries so the sizes sum to num_features.
209
+ if sum(chunks_per_audio) != num_features:
210
+ chunks_per_audio = []
211
+ for lens in audio_feature_lens:
212
+ if isinstance(lens, torch.Tensor):
213
+ n = int((lens != 0).sum())
214
+ chunks_per_audio.append(max(n, 1))
215
+ else:
216
+ chunks_per_audio.append(1)
217
+
218
+ # Use flat (not flat_from_sizes) because audio_features
219
+ # is list[Tensor] with variable-length chunks (post-unpad).
220
+ slice_idxs = [0]
221
+ for n in chunks_per_audio:
222
+ slice_idxs.append(slice_idxs[-1] + n)
223
+ audio_features_cfg = MultiModalFieldConfig.flat(
224
+ "audio",
225
+ [
226
+ slice(slice_idxs[i], slice_idxs[i + 1])
227
+ for i in range(len(chunks_per_audio))
228
+ ],
229
+ )
230
+
231
return dict(
232
**_minicpmv_field_config(hf_inputs),
178
- audio_features=MultiModalFieldConfig.batched("audio"),
233
+ audio_features=audio_features_cfg,
234
audio_feature_lens=MultiModalFieldConfig.batched("audio"),
235
audio_embeds=MultiModalFieldConfig.batched("audio"),
236
)
@@ -364,11 +419,23 @@ class MiniCPMOMultiModalProcessor(MiniCPMVMultiModalProcessor[MiniCPMOProcessing
419
420
# Avoid padding since we need the output for each audio to be
421
# independent of other audios for the cache to work correctly
422
+ # Flatten audio_feature_lens (list of tensors of any
423
+ # dimensionality, one per audio, each containing per-chunk
424
+ # lengths) into a flat list of integer lengths so there is
425
+ # one length per chunk, matching the first dimension of
426
+ # audio_features. Using flatten() handles 0-D, 1-D, and
427
+ # higher-dimensional tensors uniformly.
428
+ flat_feature_lens: list[int] = []
429
+ for lens in audio_inputs["audio_feature_lens"]:
430
+ if isinstance(lens, torch.Tensor):
431
+ flat_feature_lens.extend(lens.flatten().tolist())
432
+ else:
433
+ flat_feature_lens.append(int(lens))
434
unpadded_audio_features = [
368
- feat[:, :feature_len]
369
- for feat, feature_len in zip(
435
+ feat[:, :length]
436
+ for feat, length in zip(
437
audio_inputs["audio_features"],
371
- audio_inputs["audio_feature_lens"],
438
+ flat_feature_lens,
439
)
440
]
441
audio_inputs["audio_features"] = unpadded_audio_features