Skip to content

Add Parakeet CTC automatic speech recognition support - #471

Merged
justinchuby merged 8 commits into
mainfrom
justinchuby-add-parakeet-ctc
Aug 13, 2026
Merged

Add Parakeet CTC automatic speech recognition support#471
justinchuby merged 8 commits into
mainfrom
justinchuby-add-parakeet-ctc

Conversation

@justinchuby

Copy link
Copy Markdown
Member

Summary

Add first-class Mobius support for nvidia/parakeet-ctc-1.1b, Hugging Face model_type: parakeet_ctc.

This is an independent offline CTC ASR architecture and does not duplicate #411, which targets streaming Parakeet RNNT. The new path consumes processor-normalized log-mel features and produces frame-level CTC logits.

Architecture

  • Symmetric 8x depthwise Conv2d FastConformer subsampling
  • Transformer-XL relative positional self-attention with learned bias_u/bias_v
  • Macaron feed-forward blocks
  • BatchNorm Conformer convolution modules
  • 42-layer, hidden-size 1024 encoder and 1025-class Conv1d CTC head
  • Feature-input contract: input_features [B, T, 80] plus boolean attention_mask
  • Direct Hugging Face parameter-name alignment; preprocessing only removes BatchNorm num_batches_tracked

The reusable component surface also gains grouped/bias-free Conv1d and frozen BatchNorm1d inference with fp32 accumulation.

Model and golden integration

  • Register parakeet_ctc config/model/task extraction
  • Add FeatureCTCAsrTask
  • Add feature-ctc-asr YAML/schema and golden generation support
  • Pin config and every checkpoint shard to revision 20e63a0fed6aedba145b74b826dbd41df0941730
  • Add exact frame-count enforcement for deterministic CTC L5 goldens
  • Add explicit ORT GenAI export rejection for this unsupported feature-input CTC contract

Committed real-audio goldens use nonzero LibriSpeech audio and contain all 114 frame argmax IDs plus the full decoded transcript:

cauliflower mayonnaise take cold boiled cauliflower break into branches adding salt pepper and vinegar to season

Validation

GPU: NVIDIA RTX A1000 Laptop GPU, 8 GB; CUDA and CUDAExecutionProvider available.

  • python -m pytest tests/build_graph_test.py tests/cli_test.py src/ -q -k "not phi4mm and not apply_weights_unknown" --tb=short -n auto
    • 3639 passed, 57 skipped
  • python -m pytest tests/arch_validation_test.py -k parakeet -q --tb=short
    • 3 passed, 874 deselected
  • python -m pytest tests/yaml_schema_test.py -q --tb=short
    • 237 passed
  • Real-checkpoint CUDA parity, fp32:
    • passed
    • max absolute difference: 0.000076
    • mean absolute difference: 0.000014
  • Real-checkpoint CUDA fp16:
    • passed
    • exact 114/114 frame IDs
    • exact full transcript
  • CUDA L4 checkpoint golden and L5 deterministic CTC transcript/frame golden:
    • 2 passed, 377 deselected
  • lintrunner -a
    • no issues
  • Automated high-confidence code review after fixes:
    • no significant issues found

CLI/runtime/quantization evidence

  • fp16 CLI CUDA export loaded and ran with ONNX Runtime CUDA EP
  • Runtime produced the exact 114 golden frame IDs and exact full transcript
  • Olive 0.13.0 INT4 RTN quantization produced a 751 MB model
  • Quantized CUDA inference produced the same full transcript

Evidence-based limitations and waivers

  • BF16 disabled: Hugging Face bf16 reference output is correct, and the Mobius graph executes under ORT CUDA after avoiding unsupported kernels, but ORT output collapses to blank CTC predictions. Parakeet therefore defaults safely to fp32 and rejects explicit bf16; fp32 and fp16 are verified. This avoids exposing a configuration that runs without error but returns incorrect ASR results.
  • ORT GenAI / Foundry Local waived: ORT GenAI 0.15.2 rejects input_features in its decoder model schema. This offline feature-input CTC model cannot be represented by the current ORT GenAI decoder contract, so Mobius now fails explicitly rather than producing a misleading package. Foundry Local depends on ORT GenAI and is consequently not applicable until that runtime supports feature-input CTC pipelines.
  • Safetensors package output: the installed onnx_ir failed during safetensors CLI serialization; standard ONNX external-data export succeeded and was used for CUDA runtime and quantization validation.

Implement the NVIDIA FastConformer encoder, feature-input CTC task, processor-aware golden infrastructure, and Hugging Face weight alignment for parakeet_ctc.

Add synthetic and real-checkpoint parity coverage, deterministic audio goldens, pinned revision loading, CUDA fp16 validation, and explicit unsupported-runtime guards.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby
justinchuby requested review from a team and a lite review from Copilot August 10, 2026 18:17
Comment thread src/mobius/components/_parakeet_audio.py Fixed
Comment thread tests/parakeet_ctc_integration_test.py Fixed
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Performance Comparison

Comparing ed0319d9abd39c

Model Metric Baseline Current Delta
bert (feature-extraction) model_size_bytes 359 KB 359 KB +0.0%
bert (feature-extraction) num_nodes 60 60 +0.0%
falcon model_size_bytes 364 KB 364 KB +0.0%
falcon num_nodes 66 66 +0.0%
gemma2 model_size_bytes 428 KB 428 KB +0.0%
gemma2 num_nodes 105 105 +0.0%
gpt2 model_size_bytes 388 KB 388 KB +0.0%
gpt2 num_nodes 54 54 +0.0%
llama model_size_bytes 425 KB 425 KB +0.0%
llama num_nodes 60 60 +0.0%
llama (static-cache) model_size_bytes 425 KB 425 KB +0.0%
llama (static-cache) num_nodes 56 56 +0.0%
mamba (ssm-text-generation) model_size_bytes 296 KB 296 KB +0.0%
mamba (ssm-text-generation) num_nodes 94 94 +0.0%
phi3 model_size_bytes 421 KB 421 KB +0.0%
phi3 num_nodes 58 58 +0.0%
phi3 (static-cache) model_size_bytes 421 KB 421 KB +0.0%
phi3 (static-cache) num_nodes 54 54 +0.0%
qwen2 model_size_bytes 425 KB 425 KB +0.0%
qwen2 num_nodes 60 60 +0.0%
qwen2 (static-cache) model_size_bytes 425 KB 425 KB +0.0%
qwen2 (static-cache) num_nodes 56 56 +0.0%
qwen3_5_moe (hybrid-text-generation) model_size_bytes 506 KB 506 KB +0.0%
qwen3_5_moe (hybrid-text-generation) num_nodes 264 264 +0.0%
qwen3_5_text (hybrid-text-generation) model_size_bytes 458 KB 458 KB +0.0%
qwen3_5_text (hybrid-text-generation) num_nodes 126 126 +0.0%
qwen3_5_vl (hybrid-qwen-vl) model_size_bytes 977 KB 977 KB +0.0%
qwen3_5_vl (hybrid-qwen-vl) num_nodes 428 428 +0.0%
t5 (seq2seq) model_size_bytes 836 KB 836 KB +0.0%
t5 (seq2seq) num_nodes 166 166 +0.0%
whisper (speech-to-text) model_size_bytes 1008 KB 1008 KB +0.0%
whisper (speech-to-text) num_nodes 128 128 +0.0%

No performance regressions.

Format the new FastConformer component and CUDA integration test with the Ruff 0.16.1 version pinned by CI.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class Mobius support for the Hugging Face parakeet_ctc architecture (nvidia/parakeet-ctc-1.1b) by introducing a feature-input CTC ASR task (log-mel features + frame mask → frame logits), the Parakeet FastConformer encoder implementation, registration/config plumbing, and deterministic golden/integration coverage.

Changes:

  • Implement Parakeet CTC model/config/components and register model_type: parakeet_ctc with a new feature-ctc-asr task.
  • Extend golden generation and e2e golden execution to support feature-input CTC and revision-pinned builds (plus deterministic frame-count enforcement for CTC L5).
  • Add ORT GenAI export guardrails for this unsupported feature-input CTC contract, plus new unit/integration tests and goldens.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/parakeet_ctc_integration_test.py New real-audio, real-weight CUDA parity + fp16 frame-ID validation for Parakeet CTC.
tests/e2e_golden_test.py Thread revision into build; add feature-ctc-asr feed prep + CTC generation path and deterministic frame-count enforcement.
tests/build_graph_test.py Include feature-ctc-asr in expected package-role mapping.
tests/_test_configs.py Add a tiny parakeet_ctc test config entry for graph/unit coverage.
testdata/golden/audio/parakeet-ctc-1.1b.json New L4 golden summary for Parakeet CTC.
testdata/golden/audio/parakeet-ctc-1.1b_generation.json New L5 deterministic frame argmax IDs + transcript golden for Parakeet CTC.
testdata/cases/schema.json Register feature-ctc-asr as a valid task_type.
testdata/cases/audio/parakeet-ctc-1.1b.yaml New L4+L5 Parakeet CTC real-audio case pinned to a specific revision.
src/mobius/tasks/_ctc_asr.py Add FeatureCTCAsrTask (feature-input CTC) alongside existing waveform CTC task.
src/mobius/tasks/init.py Export/register FeatureCTCAsrTask in the task registry.
src/mobius/models/parakeet_ctc.py New ParakeetForCTCModel implementing encoder + Conv1d CTC head and bf16 rejection.
src/mobius/models/parakeet_ctc_test.py New unit tests for config extraction, bf16 rejection, weight-name alignment, parity, ORT GenAI export rejection.
src/mobius/models/init.py Export ParakeetForCTCModel.
src/mobius/integrations/ort_genai/auto_export.py Explicitly reject ORT GenAI export for parakeet_ctc models.
src/mobius/components/_whisper.py Generalize Conv1d to support groups and optional bias.
src/mobius/components/_parakeet_audio.py New offline FastConformer components used by Parakeet CTC encoder.
src/mobius/components/_conv.py Add BatchNorm1d implemented via elementwise inference math (fp32 accumulation).
src/mobius/components/init.py Export BatchNorm1d and ParakeetFastConformerEncoder.
src/mobius/_weight_loading.py Add revision-aware parallel shard download and revision-aware _download_weights.
src/mobius/_registry.py Register parakeet_ctc model/task/config and add a default model-id mapping.
src/mobius/_configs/_base.py Add ParakeetCTCConfig with nested encoder extraction + safe dtype defaulting.
src/mobius/_configs/init.py Export ParakeetCTCConfig.
src/mobius/_config_resolver.py Make direct config.json fetch revision-aware.
src/mobius/_builder.py Add revision parameter and thread it through config + weight loading.
scripts/generate_golden.py Extend CTC golden generation to support revision + AutoModelForCTC (MMS-special-casing preserved).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/e2e_golden_test.py
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

🏗️ Architecture Diff

Comparing ed0319d9abd39c

Model Sub-model Changes Status
bert (feature-extraction) model 0
falcon model 0
gemma2 model 0
gemma4 (gemma4) decoder 0
gemma4 (gemma4) embedding 0
gemma4 (gemma4) vision_encoder 0
gemma4_text model 0
gpt2 model 0
llama model 0
llama (static-cache) model 0
mamba (ssm-text-generation) model 0
phi3 model 0
phi3 (static-cache) model 0
qwen model 0
qwen (static-cache) model 0
qwen2 model 0
qwen2 (static-cache) model 0
qwen2_moe model 0
qwen2_moe (static-cache) model 0
qwen3 model 0
qwen3 (static-cache) model 0
qwen3_5_moe (hybrid-text-generation) model 0
qwen3_5_text (hybrid-text-generation) model 0
qwen3_5_vl (hybrid-qwen-vl) decoder 0
qwen3_5_vl (hybrid-qwen-vl) embedding 0
qwen3_5_vl (hybrid-qwen-vl) vision_encoder 0
qwen3_moe model 0
qwen3_moe (static-cache) model 0
qwen3_next (hybrid-text-generation) model 0
t5 (seq2seq) decoder 0
t5 (seq2seq) encoder 0
whisper (speech-to-text) decoder 0
whisper (speech-to-text) encoder 2 🔵
whisper (speech-to-text) / encoder — 2 change(s)

Op summary: 50 → 50 nodes

No op-sequence changes.

Modified attributes:

  • node[0] Conv: group: None → 1
  • node[2] Conv: group: None → 1

Legend: ⚪ No change · 🔵 Minor (attrs/inits) · 🟡 Moderate (nodes added/removed) · 🔴 Major (interface changed)

@justinchuby

Copy link
Copy Markdown
Member Author

CI baseline / unrelated-failure analysis (2026-08-10)

The remaining failures in CI run 31418606770 are outside the Parakeet change surface:

  • Dedicated L3 job 93553773549 fails only bamba_0 and bamba_1. The reported values are max_abs_diff=0.001375, mean_abs_diff=0.000201, cosine 0.999997, argmax match true; and max_abs_diff=0.001662, mean_abs_diff=0.000172, cosine 0.999996, argmax match true.
  • Every platform job (Ubuntu and Windows, Python 3.11/3.12/3.13) has the same two Bamba failures and no Parakeet-specific failure. The six job IDs are 93553709286, 93553709345, 93553709364, 93553709475, 93553709369, and 93553709299.
  • Integration(fast) job 93553709271 fails only test_deepseek_v2_lite_prefill_logits_match and test_deepseek_non_mla_decoder_prefill_logits_match (2 failed, 16 passed, 4 skipped, 100 deselected).
  • This PR does not modify Bamba or DeepSeek model/test code. No unrelated tolerance or model changes are included to mask those failures.

The exact base SHA is 78437cd01b2391a53c757bd3d06850ff493494ae. Its main CI run 31230202537 is itself red: L4 and L5 each time out on the unrelated olmoe-1b-7b and qwen1_5-moe cases. This confirms that the base was not fully green before the Parakeet commit; it does not claim that the older base run reproduced the later Bamba/DeepSeek failures.

Parakeet-specific L1 is green in job 93553773623. Local CUDA L4/L5 and real-checkpoint fp32/fp16 validations are documented in the PR body; GitHub L4/L5 are still running in this CI run and will be checked to completion.

justinchuby and others added 3 commits August 10, 2026 13:16
Remove the broad cache fallback from L4 and L5 so a changed golden model set cannot restore unrelated checkpoints and exhaust the hosted GPU runner disk.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Patch the runtime Hugging Face hub and Xet cache constants for each golden test, then remove that cache at teardown so all-model GPU runs do not accumulate checkpoints until the runner disk is full.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
Expose the reusable affected-model input to manual L4 and L5 dispatches so model-specific hosted validation can run independently of unrelated all-model baseline failures.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby

Copy link
Copy Markdown
Member Author

Hosted Parakeet golden follow-up

The Parakeet-specific validation is now complete on the hosted GPU runner at head 3262860d8af4bb63aa4c9fb098f7dacc42d86d0a:

  • L1 smoke job 93553773623: passed.
  • Targeted L4 run 31485270551, job 93759094978: passed; the checkpoint test step completed in 2m04s.
  • Targeted L5 run 31485270592, job 93759095610: passed; the generation test step completed in 2m16s.

The earlier aggregate L4/L5 failures were infrastructure-only. The first two attempts exhausted the self-hosted runner disk because HF_HOME was changed after huggingface_hub had captured process-global cache constants, and Xet chunks were not redirected or cleaned. Commit 0daf582 now patches the hub/assets/Xet runtime cache constants per test and eagerly deletes each cache at teardown; local validation confirmed both Parakeet CUDA goldens pass and both test caches are absent afterward. The subsequent aggregate jobs no longer exhausted disk, but hit the existing one-hour all-model workflow ceiling, consistent with the already-red base golden runs.

Commit 3262860 exposes the existing affected-model input to manual dispatch, allowing the successful hosted Parakeet-only evidence above without changing, skipping, or loosening unrelated Bamba/DeepSeek tests.

@justinchuby justinchuby left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Correctness review: two findings.

src/mobius/_builder.py:539: the new revision argument is dropped on the diffusers fallback. If AutoConfig fails and this path is selected, the pipeline index/configs/weights come from the repository default revision rather than the requested commit. Please thread revision through build_diffusers_pipeline and its Hub downloads.

Comment thread src/mobius/components/_parakeet_audio.py Outdated
Use the configured Parakeet activation in feed-forward and convolution modules. Propagate build revisions through diffusers artifacts and pin all golden-test Hugging Face input artifacts to each case revision.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: justinchuby <justinchuby@users.noreply.github.com>
@justinchuby

Copy link
Copy Markdown
Member Author

Also fixed the review-summary finding in 612f3eb: revision is now propagated through the diffusers fallback, pipeline index, component configs, weight indexes/files, and parallel shard downloads, with targeted no-network tests.

Update the Parakeet branch to current main while retaining all newly added model registrations. Emit frozen BatchNorm1d as standard BatchNormalization so ORT can fold it into neighboring convolutions, and assert the optimized Parakeet graph keeps fused Attention, Swish, BatchNormalization, and SkipLayerNormalization operators.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby

Copy link
Copy Markdown
Member Author

Updated PR #471 to current main (1e6f61f) in merge commit dd1122e and revalidated Parakeet's optimized graph.

Optimization/fusion evidence:

  • Tiny 2-layer graph: 406 raw nodes -> 270 after Mobius optimization -> 219 after ORT CUDA optimization.
  • Mobius graph retains 2 opset-24 Attention, 8 SkipLayerNormalization, 6 native opset-24 Swish, and 2 BatchNormalization nodes.
  • Frozen BatchNorm1d now emits standard BatchNormalization; ORT CUDA folds both BatchNorm nodes into their adjacent convolutions (2 -> 0 in the optimized graph).
  • ORT CUDA lowers the six native Swish nodes to six com.microsoft::QuickGelu kernels with alpha 1.
  • Relative-position attention requires an explicit additive bias, so Flash Attention is not eligible; fused ONNX Attention remains the correct representation and FP16 can use MEA when sequence alignment permits.

Post-merge validation:

  • Full non-integration suite: 3867 passed, 58 skipped.
  • Merged targeted tests: 50 passed; fused graph tests: 15 passed; Parakeet schema/architecture selection: 4 passed.
  • lintrunner -a: no issues.
  • Real FP32 CUDA parity: max absolute difference 0.000137, mean 0.000014.
  • Real FP16 CUDA: exact 114 frame IDs and exact transcript.
  • CUDA L4/L5 Parakeet goldens: 2 passed.
  • Focused automated code review found no significant issues.

Bring the Parakeet branch to main at ed0319d while retaining both speech-recognition architectures. Preserve Conv1d positional bias compatibility and add grouped convolution support required by Parakeet depthwise blocks, with regression coverage.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Justin Chu <justinchu@microsoft.com>
@justinchuby

Copy link
Copy Markdown
Member Author

Final main refresh completed in 9abd39c: PR #471 now includes main@ed0319d (Moonshine ASR) while retaining Parakeet CTC and the graph-fusion changes.

The only new integration conflict was the shared Whisper/Moonshine Conv1d: the resolution preserves the existing positional bias API and adds grouped weights/group dispatch for Parakeet depthwise convolution. Automated review caught and the branch now covers positional-bias compatibility explicitly.

Final post-merge evidence:

  • Full non-integration suite from this worktree: 3880 passed, 58 skipped.
  • Focused Parakeet/Moonshine/Whisper/BatchNorm suite: 49 passed.
  • lintrunner -a: no issues.
  • Final tiny Parakeet optimized graph: 188 nodes, including exactly 1 Attention, 1 BatchNormalization, 3 Swish, 4 SkipLayerNormalization, and 0 Sqrt nodes.
  • Hosted replacement Lint: passed.
  • Hosted replacement Architecture Diff: passed.

Earlier real-checkpoint CUDA FP32/FP16 and hosted Parakeet-only L4/L5 evidence remains applicable because the latest merge did not alter Parakeet math; its only shared-component resolution preserves the already-validated grouped Conv1d graph and is covered by the graph tests above.

@justinchuby
justinchuby merged commit 62b093e into main Aug 13, 2026
20 of 23 checks passed
@justinchuby
justinchuby deleted the justinchuby-add-parakeet-ctc branch August 13, 2026 23:48
justinchuby added a commit that referenced this pull request Aug 14, 2026
## Summary

- distill post-single-shot lessons from the Parakeet CTC, Mage-VL,
Nemotron Parse, LFM2.5, Moonshine, MiniCPM-V, Qwen Image Edit, and Muse
Glimmer integrations
- tighten source/config/revision fidelity, real processor and runtime
contracts, semantic multi-dtype validation, exact golden testing, and
weighted graph optimization evidence
- add precise CI baseline triage, targeted GPU validation, linear
rebase/worktree guidance, quantization schema checks, and executable
diffusion pipeline requirements
- shorten the duplicated multimodal float32 input section and resolve
contradictory encoder/component import guidance

## Sources

Direct agent retrospectives plus commit/review history for merged PRs
#462-#465, #471-#473, and #475.

## Validation

- documentation diff is whitespace-clean
- initialized repository-pinned Ruff/lintrunner tooling
- independent rubber-duck review found no blocking issues; follow-up
consistency suggestions were applied

No runtime code is changed.

---------

Signed-off-by: Justin Chu <justinchu@microsoft.com>
Signed-off-by: Justin Chu <justinchuby@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants