Audio: add Qwen3-ASR adapter - #2257
Conversation
b8ad3df to
44510a2
Compare
Greptile SummaryThe PR adds a Qwen3-ASR implementation of the shared ASR adapter and extends the generic stage to persist nested adapter metadata while retaining Qwen-Omni support.
Confidence Score: 5/5The PR appears safe to merge because no blocking failure remains in the available follow-up review scope. No blocking failure remains. Important Files Changed
Sequence DiagramsequenceDiagram
participant Manifest as ManifestReader
participant Resample as ResampleAudioStage
participant Stage as ASRStage
participant Adapter as QwenASRAdapter
participant Model as Qwen3ASRModel.LLM
participant Writer as ManifestWriterStage
Manifest->>Resample: AudioTask with source path
Resample->>Stage: Resampled PCM WAV path
Stage->>Stage: Decode, mono-convert, resample
Stage->>Adapter: waveform, sample rate, language
Adapter->>Model: transcribe(audio, language)
Model-->>Adapter: text and detected language
Adapter-->>Stage: Ordered ASRResult list
Stage->>Stage: Write prediction, skip state, and asr_extras
Stage->>Writer: Updated AudioTask
Reviews (10): Last reviewed commit: "Address latest Qwen ASR review feedback" | Re-trigger Greptile |
| # preprocessing path. | ||
| _MIN_SAMPLES = 1600 | ||
|
|
||
| _RESERVED_VLLM_KWARGS = frozenset( |
There was a problem hiding this comment.
Since this is not specific to Qwen ASR can we move it to a more generic utils file, and find out if there are other stages that can use it?
| @classmethod | ||
| def download_weights_on_node(cls, model_id: str, revision: str | None = None) -> None: | ||
| """Populate the local Hugging Face cache without allocating a GPU.""" | ||
| from huggingface_hub import snapshot_download |
There was a problem hiding this comment.
Can we move most if not all of these imports to the top of the file please?
| return [] | ||
| if self._model is None: | ||
| msg = "QwenASRAdapter is not initialized; call load_model() first" | ||
| raise RuntimeError(msg) |
There was a problem hiding this comment.
Let's remove this block, if the user is running it correctly in a pipeline then it should never reach.
|
|
||
| # ---------------------------------------------------------------------- | ||
| # Contract conformance and construction validation | ||
| # ---------------------------------------------------------------------- |
There was a problem hiding this comment.
Can we remove the claude comments please.
There was a problem hiding this comment.
The GPU tests can be with the other tests in test_qwen_asr with @pytest.mark.gpu.
| # Qwen3-ASR adapter; compose qwen-asr with Curator's shared vLLM stack. Do not | ||
| # use qwen-asr[vllm], whose vLLM 0.14.0 pin conflicts with Curator's current | ||
| # Qwen-Omni-compatible vLLM version. | ||
| audio_qwen_asr = [ |
There was a problem hiding this comment.
Any reason why we can't just add this to audio_cuda12?
virajkarandikar
left a comment
There was a problem hiding this comment.
lgtm. vllm kwargs can be moved to utils.
991f288 to
ec06d02
Compare
| return Qwen3ASRModel | ||
|
|
||
|
|
||
| def _patch_transformers_compat() -> None: |
There was a problem hiding this comment.
Instead of patching should we just use the actual compatible Transformers version? We could do it via the stage's runtime_env maybe?
| @pytest.mark.parametrize( | ||
| "reserved_key", | ||
| [ | ||
| "model", |
There was a problem hiding this comment.
Can this list be imported from somewhere?
| ) | ||
|
|
||
|
|
||
| class TestValidateVllmKwargs: |
There was a problem hiding this comment.
Nit but can we not have 2 separate test classes for validate/merge please.
0d642be to
493ef57
Compare
Signed-off-by: aaftaabv@gmail.com <aaftaabv@gmail.com>
Signed-off-by: aaftaabv@gmail.com <aaftaabv@gmail.com>
Signed-off-by: aaftaabv@gmail.com <aaftaabv@gmail.com>
493ef57 to
23138d5
Compare
Signed-off-by: aaftaabv@gmail.com <aaftaabv@gmail.com>
23138d5 to
f5d42df
Compare
|
/ok to test f5d42df |
Summary
Add Qwen3-ASR as a second implementation of Curator's shared
ASRAdaptercontract.The PR keeps both adapters:
QwenASRAdapterforQwen/Qwen3-ASR-0.6B, using qwen-asr's vLLM-onlyQwen3ASRModel.LLMpath.QwenOmniASRAdapter, Qwen3-Omni pipeline, dependency contract, tests, and vLLM behavior remain functionally unchanged.There is no standalone Qwen-ASR runner. Manifest transcription uses the generic
ASRStageadapter path.Qwen3-ASR adapter
download_weights_on_node,load_model,unload_model, andtranscribe_batch.Qwen3ASRModel.LLMwith the same engine arguments asnkoluguri/integration-test: model, GPU-memory utilization, inference batch size, max new tokens, remote-code trust, eager execution, prefix caching, andxxhash..from_pretrainedmodel loading or inference implementation.transformers.check_model_inputscompatibility shim as the nkoluguri reference because qwen-asr 0.0.6 still invokes the decorator-factory form.transcribecall while preserving input order and skipped positions.revisionto weight download and vLLM construction.vllm_kwargsdictionary; adapter-owned engine arguments cannot be overridden through it.ASRResult.extras.audio_cuda12pinsqwen-asr==0.0.6. Qwen-ASR installations compose it with Curator's sharedvllmextra. The dependency intentionally does not useqwen-asr[vllm], whose vLLM 0.14.0 pin conflicts with Curator's Qwen-Omni-compatible vLLM 0.22.0 stack.Generic adapter extras
ASRStagecan persist arbitrary adapter metadata without introducing dynamic top-level columns:ASRResult.extrasremains one generic adapter-owned dictionary.ASRStage.extras_keyto write a shallow copy under one nested manifest field.extras_key=Noneis the default, preserving the existing Qwen-Omni output contract and existing ASRStage callers.extras_key: asr_extras, producing"asr_extras": {"detected_language": "English"}._skipme, oradditional_notescolumns are rejected.outputs(), so executor/schema planning remains deterministic.Shared stage, tests, and tutorial
tutorials/audio/qwen_asr/usingManifestReader -> ResampleAudioStage -> ASRStage(QwenASRAdapter) -> ManifestWriterStage.zh, en, yue, ar, de, fr, es, pt, id, it, ko, ru, th, vi, ja, tr, hi, ms, nl, sv, da, fi, pl, cs, fil, fa, el, hu, mk, ro.tests/fixtures/audio/qwen_omni/audio_1_5s_16khz_mono.wav; this PR adds no duplicate WAV fixture.tests/models/asr/test_qwen_asr.pyunder@pytest.mark.gpuand adds theaudio_qwen_asrGPU test group.tests/fixtures/audio/tagging/sample_input.jsonlas the documented two-file smoke input.vllm_kwargs.max_model_len=8192override for 12 GB GPUs; the adapter's production/reference default is unchanged.benchmarking/README.md.Shared
validate_vllm_kwargsandmerge_vllm_kwargshelpers now live innemo_curator.utils.vllm_utils. Both Qwen adapters describe their actual caller-owned constructor kwargs tomerge_vllm_kwargs, and the duplicate adapter-local_RESERVED_VLLM_KWARGSconstants are removed. Protected-key collision checking now occurs once, inside the shared merge helper whenload_model()assembles engine kwargs; the adapters no longer repeat validation in__post_init__. Qwen-Omni's protected-key behavior, engine arguments, and output contract remain unchanged.Current-main integration
4c8ac6f6604ec71ea5919ee014e4137ee1d0e560main:09ae28c41cfb7704d66eb4d6cbffc33fc6f05fe3Validation
Current head
uv lock --checkpassed with the current-main-required uv 0.12.2.git diff --checkpassed.Local GPU and tutorial smoke
The earlier head
ddfb74cdc423dec0ffe64dae3e05fcf210b14617passed:asr_extras.detected_language == "English".The current head has not repeated that GPU smoke after the main rebase and kwargs-assembly refactor. The exact constructor tests confirm that the refactor preserves the engine arguments used by both Qwen adapters.
Latest paired Qwen3-ASR parity
The latest paired run compared target commit
ddfb74cdc423dec0ffe64dae3e05fcf210b14617withnkoluguri/integration-testcommitfff467c8d2e3632f9a96c96ec34cd0e6614503da, using the same frozen eight-row English cohort (569.486 seconds), one node, and one L40 per arm.1dc99ea4-4b0f-438d-832d-5d902384453b0443d025-95c7-42f8-a68b-ee510c9ce0e1asr_extras.detected_languagevalues matched referenceasr_language; all wereEnglish.0.9699208113126543(gate: at least0.95).0.95:7/8(gate: at least7/8).2/8; raw exact matches:1/8.0.8516129032258064.The target used qwen-asr 0.0.6 with Curator's vLLM 0.22.0 stack; the remote-exact reference used qwen-asr 0.0.6 with its pinned vLLM 0.14.0 stack. Timing is therefore a canary observation, not a performance comparison.
Since the parity-tested head, the branch was rebased onto current
mainand the host-side vLLM kwargs validation/assembly was centralized. The actual Qwen-ASR engine values, input contract, output mapping, and inference path are unchanged; live parity has not been rerun after this review refactor.Diff