@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 279d25f5cb
Fork 0

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