Skip to content

Update nemotron-speech-streaming-en-0.6b#3555

Merged
csukuangfj merged 5 commits into
k2-fsa:masterfrom
csukuangfj:update-nemotron
Apr 27, 2026
Merged

Update nemotron-speech-streaming-en-0.6b#3555
csukuangfj merged 5 commits into
k2-fsa:masterfrom
csukuangfj:update-nemotron

Conversation

@csukuangfj

@csukuangfj csukuangfj commented Apr 27, 2026

Copy link
Copy Markdown
Collaborator

Fixes #3408

Please see the doc at
https://k2-fsa.github.io/sherpa/onnx/nemo/nemotron-streaming.html#nemotron-asr-streaming

Screenshot 2026-04-27 at 10 13 06

cc @wangfeng35

Summary by CodeRabbit

New Features

  • Introduced Nemotron speech streaming English models with multiple chunk size options (80, 160, 560, 1120 ms)
  • Both fp32 and int8 quantization variants now available
  • Optimized streaming decoder algorithm for improved real-time performance

@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Apr 27, 2026
@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

The PR extends the nemotron-speech-streaming-en-0.6b model support by introducing multi-chunk-size exports (80/160/560/1120ms) with int8 quantization variants, updating the NeMo installation to PyPI, registering four new model variants in the APK script and Kotlin API, and modifying the transducer decoder to emit multiple symbols per frame.

Changes

Cohort / File(s) Summary
Workflow & Export Configuration
.github/workflows/export-nemotron-speech-streaming-en-0.6b.yaml
Switched NeMo installation from git branch to PyPI; restructured model export to iterate over chunk sizes (80/160/560/1120ms), exporting both fp32 and int8 variants per chunk; updated tarball naming and Hugging Face publishing target account; removed legacy publication steps.
Model Export Logic
scripts/nemo/nemotron-speech-streaming-en-0.6b/export_onnx.py
Added iteration over chunk sizes with dynamic encoder attention context configuration; exports encoder/decoder/joiner ONNX artifacts per variant; applies dynamic quantization to generate int8 models; reorganizes outputs into chunk-specific directories with metadata injection per variant.
APK Model Registration
scripts/apk/generate-asr-apk-script.py
Added four new nemotron-speech-streaming English model entries (indices 30–33) with test-wave cleanup commands.
Transducer Decoder Logic
sherpa-onnx/csrc/online-transducer-greedy-search-nemo-decoder.cc
Modified greedy search to emit up to max_symbols_per_frame non-blank symbols per encoder frame via looped joiner calls; preserves single-call behavior for blank selection and frame advancement.
Kotlin API Model Configuration
sherpa-onnx/kotlin-api/OnlineRecognizer.kt
Added model config mappings for new nemotron-speech-streaming variants (types 30–33) pointing to chunk-specific int8 ONNX artifacts and token files.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

size:XL

Poem

🐰 Chunks of sound, in sizes four,
Int8 wisely, faster more,
Symbols stream where silence fled,
Nemotron hops ahead! 🎤✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Update nemotron-speech-streaming-en-0.6b' directly matches the main objective: updating the nemotron model to a newer version with better performance.
Linked Issues check ✅ Passed The PR comprehensively addresses issue #3408 by updating the nemotron model across multiple components: workflow, APK generation, ONNX export, and Kotlin API to support the updated model version.
Out of Scope Changes check ✅ Passed All changes are directly related to updating the nemotron-speech-streaming-en-0.6b model and its supporting infrastructure; no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces support for Nemotron speech streaming models with latencies of 80ms, 160ms, 560ms, and 1120ms by updating the APK generation script, ONNX export utility, and Kotlin API. The C++ engine was also modified to support multiple symbols per frame during greedy search. Feedback identifies a critical issue where the 80ms model's chunk shift calculation results in zero, which could lead to infinite loops in the recognizer. Additionally, suggestions were made to improve the robustness of shell commands in the export script and to make the frame symbol limit configurable.

Comment on lines +72 to +103
chunk_size = ms // 80 - 1
print("chunk_size", chunk_size)
asr_model.encoder.set_default_att_context_size([70, chunk_size])

print("streaming_cfg", asr_model.encoder.streaming_cfg)
print("att_context_size", asr_model.encoder.att_context_size)
print(
"pre_encode_cache_size",
asr_model.encoder.streaming_cfg.pre_encode_cache_size,
)

print(meta_data)
if isinstance(asr_model.encoder.streaming_cfg.pre_encode_cache_size, list):
pre_encode_cache_size = (
asr_model.encoder.streaming_cfg.pre_encode_cache_size[1]
)
else:
pre_encode_cache_size = (
asr_model.encoder.streaming_cfg.pre_encode_cache_size
)

if isinstance(asr_model.encoder.streaming_cfg.chunk_size, list):
chunk_size = asr_model.encoder.streaming_cfg.chunk_size[1]
else:
chunk_size = asr_model.encoder.streaming_cfg.chunk_size

window_size = chunk_size + pre_encode_cache_size

print("chunk_size", chunk_size)
print("pre_encode_cache_size", pre_encode_cache_size)
print("window_size", window_size)

chunk_shift = chunk_size

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The chunk_size calculation ms // 80 - 1 results in 0 for the 80ms model. This value is assigned to chunk_shift at line 103 and subsequently stored in the model metadata. In the sherpa-onnx C++ engine (e.g., in online-recognizer-transducer-nemo-impl.h), chunk_shift is used to advance the frame pointer: ss[i]->GetNumProcessedFrames() += chunk_shift;. If chunk_shift is 0, the recognizer will enter an infinite loop and hang. Please ensure chunk_size and chunk_shift in the metadata represent the actual number of frames (e.g., 1 output frame for 80ms if the subsampling factor is 8).

Comment on lines +161 to +173
os.system(
f"""
mkdir {ms}
mv -v *.onnx {ms}
mv -v *.data {ms}
ls -lh {ms}
rm Constant_*_attr__value
rm onnx__MatMul_*
rm layers.*.conv*
rm pre_encode.conv.*.weight
ls -lh
"""
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The os.system call uses a multi-line string with significant leading indentation, which is passed literally to the shell. While most shells handle this, it is brittle and messy. Furthermore, the rm commands should use the -f flag to prevent the script from failing if the temporary files (like Constant_*_attr__value) are not present. Consider cleaning up the indentation and using -f.

        os.system(f"mkdir -p {ms}")
        os.system(f"mv -v *.onnx {ms}/")
        os.system(f"mv -v *.data {ms}/")
        os.system("rm -f Constant_*_attr__value onnx__MatMul_* layers.*.conv* pre_encode.conv.*.weight")


bool emitted = false;

int32_t max_symbols_per_frame = 10;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The max_symbols_per_frame is hardcoded to 10. It is recommended to make this value configurable via OnlineRecognizerConfig to allow users to balance between recognition thoroughness and computational cost, especially for real-time streaming applications where latency is critical.

@csukuangfj csukuangfj merged commit 415b8c2 into k2-fsa:master Apr 27, 2026
22 of 27 checks passed
@csukuangfj csukuangfj deleted the update-nemotron branch April 27, 2026 02:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Please add support for updated version of nemotron-speech-streaming-en-0.6b

1 participant