[Bugfix][Multimodal] Fix Qwen3-ASR audio preprocessing parity by MatthewCYM · Pull Request #57146 · vllm-project/vllm · GitHub
Skip to content

[Bugfix][Multimodal] Fix Qwen3-ASR audio preprocessing parity - #57146

Merged
DarkLight1337 merged 13 commits into
vllm-project:mainfrom
MatthewCYM:fix/qwen3-asr-audio-processing-20260916
Oct 12, 2026
Merged

DarkLight1337 merged 13 commits into
vllm-project:mainfrom
MatthewCYM:fix/qwen3-asr-audio-processing-20260916

Conversation

@MatthewCYM

@MatthewCYM MatthewCYM commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Purpose

Fixes #56981.

Qwen3-ASR currently inherits Omni's waveform padding and forces a Whisper feature extractor, which can change audio features and placeholder counts relative to the checkpoint's upstream processor.

Following the review feedback, this revision:

  • Uses the upstream Transformers Qwen3ASRProcessor and removes the bundled processor and its registration.
  • Requires Transformers >=5.13.0 and updates the corresponding test metadata.
  • Uses BaseMultiModalProcessor without Omni's waveform padding.
  • Processes clips independently and packs valid features, preserving parity across differently sized clips and partial cache hits.
  • Preserves text-only and precomputed-feature inputs.

Both checkpoint formats remain supported: the original checkpoint declares WhisperFeatureExtractor, while the native -hf checkpoint declares Qwen3ASRFeatureExtractor.

No shared Omni/VL implementation, model weights, encoder kernels, or speculative-decoding behavior is changed.

Test Plan

Validated against upstream main 528fa835fd37d0805a824d516e22f88df61a771a
with Transformers 5.13.0 and 5.17.0.

.venv/bin/python -m pytest \
  tests/models/multimodal/processing/test_qwen3_asr.py \
  tests/models/multimodal/processing/test_qwen3_omni.py \
  tests/multimodal/test_audio.py \
  tests/models/multimodal/processing/test_common.py \
  tests/model_executor/test_qwen3_asr_mrope.py \
  tests/entrypoints/speech_to_text/transcription/test_qwen3_asr_sanitize_prompt.py \
  tests/entrypoints/speech_to_text/transcription/test_transcription_inter_chunk_spacing.py \
  -k 'not transformers and (Qwen3-ASR or test_qwen3_asr or test_qwen3_omni or test_audio.py or ForcedAligner or test_transcription_inter_chunk_spacing)' \
  -q
  • 152 repository tests passed per Transformers version, including all 50 new regression cases.
  • Supplementary local validation passed another 63 pytest cases and four realtime-processor comparisons per version. These supplementary checks are not all included in this PR.
  • Applicable repository pre-commit hooks, the scoped manual Python 3.12 mypy hook, and whitespace checks passed.

Model validation

Tested both Qwen/Qwen3-ASR-0.6B and Qwen/Qwen3-ASR-0.6B-hf with both Transformers versions.

Each run compared raw audio against independently computed upstream features in the same vLLM engine, using 32 LibriSpeech test-clean utterances plus 32 near-hop-boundary variants. Settings: single H100, BF16, greedy decoding, eager execution, max_num_seqs=1, and processor/prefix caches disabled.

All four model/version combinations matched prompt IDs and generated token IDs on 64/64 clips. Raw/reference WER was 2.8846% in every run. This is a bounded correctness evaluation, not a full-split accuracy or speed benchmark.

Environment: Python 3.13.15, PyTorch 2.13.0+cu130, and NumPy 2.4.6. Tests used this checkout's Python source with existing vLLM 0.29 CUDA extensions, not a fresh CUDA build. Full upstream CI remains necessary. Realtime and forced-aligner checks cover preprocessing, not complete streaming or timestamp-accuracy evaluation.

Related work and disclosure

This uses the processor hook introduced by #53610; that refactor does not implement this ASR preprocessing fix. #57076 addresses the separate post-expansion truncation issue.

AI assistance was used for implementation, investigation, and test preparation.

@mergify mergify Bot added multi-modality Related to multi-modality (#4194) qwen Related to Qwen models bug Something isn't working labels Sep 16, 2026
@MatthewCYM
MatthewCYM marked this pull request as ready for review September 16, 2026 09:30

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This pull request is from a fork — automated review is disabled. A repository maintainer can comment @claude review to run a one-time review.

@github-actions

Copy link
Copy Markdown

@DarkLight1337

Copy link
Copy Markdown
Member

@ywang96 @Isotr0py would it be better to drop the native processor implementation and simply require transformeres>=5.13?

@MatthewCYM

Copy link
Copy Markdown
Contributor Author

Hi @DarkLight1337, I retained the bundled processor to preserve compatibility with Transformers 5.10.4 and existing checkpoints. Happy to switch to the upstream Transformers processor if requiring >=5.13 is preferred.

@Aatman09

Copy link
Copy Markdown

Why didn't you use the Qwen3ASRFeatureExtractor and instead used SequentialFeatureExtractor

@Isotr0py

Copy link
Copy Markdown
Member

would it be better to drop the native processor implementation and simply require transformeres>=5.13

Sure, we should remove the native ones, we only port them because of missing transfomers support at day0

Signed-off-by: MatthewCYM <chenyiming0v0@gmail.com>
@MatthewCYM
MatthewCYM force-pushed the fix/qwen3-asr-audio-processing-20260916 branch from a455f34 to 489f79d Compare September 17, 2026 09:14
@mergify mergify Bot added the ci/build label Sep 17, 2026
Qwen3OmniMoeThinkerMultiModalProcessor,
BaseMultiModalProcessor[Qwen3ASRProcessingInfo],
):
def _call_hf_processor(

@DarkLight1337 DarkLight1337 Sep 17, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please refactor this to use _get_hf_mm_text and _postprocess_hf_mm_data

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Refactored text setup and output conversion into the requested hooks. Retained per-clip processing because HF batch padding changes audio features and would break cache independence. Added regression coverage and validated both checkpoint formats with Transformers 5.13 and 5.17.

Comment thread vllm/model_executor/models/qwen3_asr.py Outdated
input_audio_features=torch.cat(features, dim=1),
feature_attention_mask=masks,
audio_feature_lengths=torch.stack([mask.sum() for mask in masks]),
audios = cast(list[AudioItem], hf_data["audio"])

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't assume that the "audio" key always exists. Take a look at how the other processors handle this

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Updated this to follow the guarded audio lookup and list assertion used in MiDashengLMMultiModalProcessor. Missing or empty audio now skips extraction, and postprocessing leaves the data unchanged when input_features is absent.

Comment thread vllm/model_executor/models/qwen3_asr.py Outdated
Comment thread requirements/common.txt Outdated
Signed-off-by: MatthewCYM <chenyiming0v0@gmail.com>
@mergify

mergify Bot commented Sep 26, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @MatthewCYM.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase label Sep 26, 2026
Signed-off-by: MatthewCYM <chenyiming0v0@gmail.com>
@mergify mergify Bot removed the needs-rebase label Sep 28, 2026
@mergify

mergify Bot commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

This pull request has merge conflicts that must be resolved before it can be
merged. Please rebase the PR, @MatthewCYM.

https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

Signed-off-by: MatthewCYM <chenyiming0v0@gmail.com>

@DarkLight1337 DarkLight1337 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks

@DarkLight1337
DarkLight1337 enabled auto-merge (squash) October 12, 2026 08:31
@DarkLight1337

Copy link
Copy Markdown
Member

/ci run --allow-stale

@github-actions github-actions Bot added the ready ONLY add when PR is ready to merge/full CI is needed label Oct 12, 2026
@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #94152 for commit eda085759a9e.

⚠️ This PR is 1 commit behind upstream main. Running CI at your own risk because --allow-stale was requested; outdated CI configuration may cause failures. Before merging, merge or rebase onto the latest main, then rerun /ci run on the latest PR commit.

@DarkLight1337

Copy link
Copy Markdown
Member

/ci run

@github-actions

Copy link
Copy Markdown

✅ Triggered Buildkite CI #94153 for commit 6bd75ab249a8.

@vllm-agent

Copy link
Copy Markdown
Collaborator

CI selector (shadow): 24 test steps (57 jobs) instead of 65 (97 jobs)

Shadow mode: this changes nothing about what CI runs. It shows what the evidence-based selector would pick for this PR, next to today's rules. How it works.

Feedback welcome: reply here if it would skip a step this change needs, or runs something unrelated.

steps (jobs) Today's rules Selector Would skip Would add
NVIDIA, CPU and others 65 (97) 24 (57) 45 (52) 4 (12)
AMD mirrors 58 (85) 17 (40) 43 (50) 2 (5)
Selector would run (24)
  • arm-cpu-test ×3
  • async-engine-inputs-utils-worker
  • basic-models-tests-extra-initialization ×14
  • basic-models-tests-initialization
  • basic-models-tests-other
  • cpu-language-generation-and-pooling-model-tests ×3
  • cpu-multi-modal-model-tests-n ×4
  • cpu-multimodal-config
  • cpu-params-env-tokenizers-parser
  • cpu-reasoning-renderers
  • distributed-model-tests-2-gpus ×3
  • entrypoints-integration-speech_to_text
  • language-models-tests-extra-standard ×2
  • language-models-tests-granite-l4-compatibility
  • language-models-tests-hybrid ×2
  • language-models-tests-standard
  • model-executor
  • multi-modal-models-standard-1-qwen2
  • multi-modal-models-standard-4-other-whisper
  • multi-modal-processor ×4
  • multi-modal-processor-cpu ×4
  • pipeline-context-parallelism-4-gpus
  • quantization ×4
  • rayexecutorv2-4-gpus
Would skip (today's rules run them) (45)
  • amd-lm-eval-small-models-harness
  • amd-qwen3-next-mtp-async-eplb-accuracy
  • ascend-npu-test
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • basic-models-test-other-cpu
  • benchmarks-cli-test
  • cpu-tool-parsers
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • metrics-tracing-2-gpus
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • rl-entrypoints-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-others-cpu
  • v1-sample
  • v1-spec-decode
Would add (today's rules do not run them) (4)
  • arm-cpu-test ×3 (code map)
  • cpu-multi-modal-model-tests-n ×4 (code map)
  • quantization ×4 (code map)
  • rayexecutorv2-4-gpus (code map)
AMD mirrors: would skip (43)
  • basic-correctness ×2
  • basic-correctness-cpu-offload
  • basic-correctness-cumem
  • basic-correctness-prefetch-offload
  • basic-correctness-sleep-mode
  • benchmarks-cli-test
  • entrypoints-integration-api-server ×4
  • entrypoints-integration-api-server-generate
  • entrypoints-integration-api-server-openai-chat_completion
  • entrypoints-integration-api-server-openai-completion
  • entrypoints-integration-llm
  • entrypoints-integration-multimodal
  • entrypoints-integration-pooling
  • entrypoints-integration-responses-api
  • fusion-e2e-quick-h100
  • fusion-e2e-tp2-ar-rms-config-sweep-h100
  • fusion-e2e-tp2-b200
  • fusion-e2e-tp2-quick-h100
  • kernels-fla-ops-test-b200
  • kernels-mhc-test-b200
  • kernels-root-misc-test-b200
  • lm-eval-small-models
  • metrics-tracing-2-gpus
  • mrcr-eval-small-models
  • multi-modal-models-standard-2-qwen3-gemma
  • multi-modal-models-standard-3-llava-qwen2-vl
  • platform-tests
  • pytorch-compilation-dynamic-shapes
  • pytorch-compilation-passes-unit-tests
  • pytorch-compilation-unit-tests
  • pytorch-compilation-unit-tests-h100
  • pytorch-fullgraph-cudagraph-l4-compatibility
  • pytorch-fullgraph-test
  • regression
  • rl-entrypoints-tests
  • v1-core
  • v1-executor-worker
  • v1-kv-connectors ×4
  • v1-kv-offload
  • v1-logits-oracle
  • v1-metrics-lmeval
  • v1-sample
  • v1-spec-decode
AMD mirrors: would add (2)
  • quantization ×4 (code map)
  • rayexecutorv2-4-gpus (code map)

4 changed files · base 99b44c7a42 · head 6bd75ab249 · Python record: build 93039 at 1e5d0ea888 · kernel record: table f26d9f4 (build 94096), map f26d9f4 · not counted: 11 build steps, 5 A100 steps the generator no longer emits, 12 optional steps the selector would also run

@MatthewCYM

Copy link
Copy Markdown
Contributor Author

/ci retry

@github-actions

Copy link
Copy Markdown

@DarkLight1337
DarkLight1337 merged commit f7a3a72 into vllm-project:main Oct 12, 2026
158 checks passed
@MatthewCYM
MatthewCYM deleted the fix/qwen3-asr-audio-processing-20260916 branch October 12, 2026 10:48
michael-gpu pushed a commit to practical-inference/vllm-ampere-extended that referenced this pull request Oct 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working ci/build multi-modality Related to multi-modality (#4194) qwen Related to Qwen models ready ONLY add when PR is ready to merge/full CI is needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Qwen3-ASR audio preprocessing produces different audio-token counts from Hugging Face

5 participants