Skip to content

fix(runtime): honor use_itn in funasr_onnx and funasr_torch SenseVoiceSmall - #3860

Open
tanishqbaweja wants to merge 1 commit into
modelscope:mainfrom
tanishqbaweja:fix/sensevoice-use-itn
Open

tanishqbaweja wants to merge 1 commit into
modelscope:mainfrom
tanishqbaweja:fix/sensevoice-use-itn

Conversation

@tanishqbaweja

Copy link
Copy Markdown
Contributor

Summary

Fixes #3859

SenseVoiceSmall.__call__ in funasr_onnx and funasr_torch reads only textnorm (default "woitn") and never use_itn. So model(wav_or_scp, language="auto", use_itn=True) sends the woitn query (15), the same as use_itn=False. That is the call in the ONNX and Libtorch demos and in the ONNX and Libtorch sections of the SenseVoice README (also README_zh.md and README_ja.md), which describes use_itn as "Whether the output result includes punctuation and inverse text normalization". SenseVoiceSmall.inference (AutoModel) sends withitn (14) for use_itn=True, as the C++ runtime does for svs_itn (default true).

The use_itn=True call came with aa3fe1a and c5f7f11, which made both wrappers read use_itn like SenseVoiceSmall.inference; the next day, 925910c ("update onnx batch inference") replaced that with the textnorm list/file reader and dropped use_itn.

This PR falls back to use_itn when no textnorm is given, in both wrappers:

textnorm_input = kwargs.get("textnorm")
if textnorm_input is None:
    textnorm_input = "withitn" if kwargs.get("use_itn", False) else "woitn"

An explicit textnorm (string, list or file) still wins, and the default stays woitn.

tests/test_runtime_sensevoice_use_itn.py runs both wrappers through the real frontend, ONNX Runtime and TorchScript on a tiny graph that returns its language and textnorm inputs as CTC tokens. A SentencePiece fixture names those ids (<|en|>, <|withitn|>, <|woitn|>), so each result shows the queries the wrapper sent. Cases: no options, use_itn=False, use_itn=True, textnorm="withitn", textnorm="woitn" with use_itn=True, and language="en" with use_itn=True, each for both backends with batch_size 1 and 2 on two files. I added the file to test-runtime-eval.yml (both path filters and the pytest command); that job already installs what it needs.

Type of change

  • Bug fix
  • Documentation
  • Example or demo
  • Runtime or deployment
  • Benchmark or evaluation
  • Model/training change

Validation

  • python -m compileall funasr examples tests
  • Docs or links checked
  • Runtime/deployment command tested

Windows 11, CPU, in two environments: Python 3.11.17 with torch 2.10.0+cpu and numpy 2.4.6, and Python 3.10.22 with the workflow's pins (torch 2.8.0+cpu, numpy 1.26.4); both with onnx 1.19.0 and onnxruntime 1.23.2.

  • python -m pytest -q tests/test_runtime_sensevoice_use_itn.py with the wrappers of main (20f26b7): 8 failed, 16 passed in both environments. The failures are the cases that pass use_itn=True without textnorm, which return ['<|woitn|>', '<|woitn|>'] (<|en|><|woitn|> with language="en"). On this branch: 24 passed.
  • The workflow's command, python -m pytest -q tests/test_runtime_eval_cli.py tests/test_runtime_eval_native.py tests/test_runtime_sensevoice_use_itn.py, on this branch: 76 passed in both environments.
  • black --line-length=100 (24.4.0, the pre-commit pin) leaves the new test unchanged and reports nothing in the changed lines of the wrappers. git diff --check is clean.

User impact

funasr_onnx and funasr_torch users who pass use_itn=True, as the demos and READMEs do, get the withitn query, as with AutoModel, instead of a silent woitn. Calls without use_itn or with textnorm are unchanged.

Notes for reviewers

  • I did not run the real SenseVoiceSmall weights (no model downloads here). The test checks the query ids the wrappers send, not recognition output.
  • The test runs on the CPU only: like the hotword wrappers, the Torch wrapper loads the TorchScript module without map_location. Not changed here.
  • fix demo onnx textnorm QwenAudio/SenseVoice#176 worked around this in that repo's demo_onnx.py (use_itn=True became textnorm="withitn"). With this fix, the ten ONNX and Libtorch use_itn=True calls in this repo's demos and READMEs work as written.

…eSmall

SenseVoiceSmall.__call__ in funasr_onnx and funasr_torch read only the
textnorm keyword and defaulted it to "woitn", so use_itn was ignored.
model(wavs, language="auto", use_itn=True), the call in the ONNX and
Libtorch demos and in the SenseVoice READMEs, sent the woitn query (15)
like use_itn=False, so the model was asked for text without punctuation
and inverse text normalization. Both wrappers read use_itn until
925910c replaced it with the textnorm list/file reader.

Fall back to use_itn when textnorm is not given, as
SenseVoiceSmall.inference does for text_norm. An explicit textnorm
still wins, and the default stays woitn.

Add tests/test_runtime_sensevoice_use_itn.py, which runs both wrappers
on a tiny graph that returns its language and textnorm queries as CTC
tokens, exported to ONNX and traced to TorchScript, and run it in the
runtime evaluation workflow.
LauraGPT added a commit that referenced this pull request Nov 9, 2026
Preserve the original PR #3860 commit and use_itn fallback. Retain singleton query tags independently while slicing per-utterance language and textnorm inputs. Add real ONNX/TorchScript regressions for lists, files and partial batches.

Signed-off-by: LauraGPT <zhifu.gzf@alibaba-inc.com>

@LauraGPT LauraGPT left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I reproduced the ignored use_itn=True behavior and validated this fallback. While testing the real wrappers, I also found an existing adjacent batching defect: singleton language resets per-utterance textnorm values in later batches, while singleton textnorm can become an empty tensor when languages vary. The empty tensor triggered an actual ONNX CUDA illegal memory access in the analytic regression fixture.

Companion #3861 preserves your original commit and authorship and adds independent scalar/list slicing plus mixed-tag and short-tail regressions. Its fixed tree passed 112 related CPU cases and 96 actual L20Z ONNX/TorchScript CUDA contract cases; all 6 exact-head CI checks and their downloaded evidence passed. These are runtime-routing tests with generated fixtures, not pretrained ASR accuracy claims.

The full repository suite remains unresolved at an unchanged online Conformer test that needs an uncached model (79 passed, 1 skipped, 1 failed before stopping). No new pretrained weights were downloaded, and neither this change nor its companion has been merged or released.

@tanishqbaweja

Copy link
Copy Markdown
Contributor Author

Thanks for reproducing it on the real wrappers, and for #3861. Slicing language and textnorm independently there also covers the mixed-tag batches this PR didn't touch.

This branch has not been deployed

No deployments
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.

funasr_onnx and funasr_torch SenseVoiceSmall ignore use_itn: use_itn=True still sends the woitn query

2 participants