Spoken language identification for de, en, es, fr, it, he, nl, pt, sv, tr,
derived from openai/whisper-tiny and packaged for
sherpa-onnx.
This repo was rebuilt from scratch and the previous revision used a different method. The decoder here has a 10-entry vocabulary — it is not interchangeable with a stock Whisper export. Do not mix files across revisions.
| File | Notes |
|---|---|
tiny-encoder.int8.onnx | Audio encoder. Carries the sherpa-onnx metadata_props, including the language mapping. |
tiny-decoder.int8.onnx | Single-step decoder, pruned to 10 language logits. |
No tokens.txt is needed: sherpa-onnx reads all_language_codes from the
encoder metadata, and the decoder no longer has a text vocabulary.
LID needs exactly one decoder step — feed <|startoftranscript|>, read the
logits at the language-token positions. Everything else in the decoder's
vocabulary machinery is dead weight, so it was removed losslessly (no
retraining, no distillation):
[51865, 384] → [1, 384] — only <|sot|> is ever fed.[384, 51865] → [384, 10] — only the 10 language rows kept.i maps to LANGS[i]:
n_vocab=10, sot=0, all_language_tokens=0..9, all_language_codes set
to the 10 codes. Unused ids (eot, translate, transcribe,
no_timestamps, no_speech, …) are clamped to 0 so nothing indexes out of
bounds.That takes the pair from ~37M to ~17M parameters. Quantization is applied after
pruning: dynamic, per-channel, MatMul only (MatMulConstBOnly). Conv
layers stay fp32 — dynamic int8 Conv isn't well supported and that's where most
of the encoder's accuracy lives. metadata_props is re-attached after
quantization, since ORT's quantizer drops it.
import sherpa_onnx
config = sherpa_onnx.SpokenLanguageIdentificationConfig(
whisper=sherpa_onnx.SpokenLanguageIdentificationWhisperConfig(
encoder="tiny-encoder.int8.onnx",
decoder="tiny-decoder.int8.onnx",
),
num_threads=1,
provider="cpu",
)
slid = sherpa_onnx.SpokenLanguageIdentification(config)
s = slid.create_stream()
samples, sample_rate = sherpa_onnx.read_wave("test.wav") # 16 kHz mono
s.accept_waveform(sample_rate, samples)
print(slid.compute(s)) # -> 'he'
Plain onnxruntime works too. Run the encoder, then one decoder step with
tokens=[[0]] (sot is remapped to 0) and zeroed self-attention caches; softmax
over the 10 logits. See check_lid.py in the source repo.
he; Whisper's older exports call it iw. Both are accepted by the
pruning script, the metadata emits he.MIT, following openai/whisper-tiny.
3 commits
Spoken language identification for de, en, es, fr, it, he, nl, pt, sv, tr,
derived from openai/whisper-tiny and packaged for
sherpa-onnx.
This repo was rebuilt from scratch and the previous revision used a different method. The decoder here has a 10-entry vocabulary — it is not interchangeable with a stock Whisper export. Do not mix files across revisions.
| File | Notes |
|---|---|
tiny-encoder.int8.onnx | Audio encoder. Carries the sherpa-onnx metadata_props, including the language mapping. |
tiny-decoder.int8.onnx | Single-step decoder, pruned to 10 language logits. |
No tokens.txt is needed: sherpa-onnx reads all_language_codes from the
encoder metadata, and the decoder no longer has a text vocabulary.
LID needs exactly one decoder step — feed <|startoftranscript|>, read the
logits at the language-token positions. Everything else in the decoder's
vocabulary machinery is dead weight, so it was removed losslessly (no
retraining, no distillation):
[51865, 384] → [1, 384] — only <|sot|> is ever fed.[384, 51865] → [384, 10] — only the 10 language rows kept.i maps to LANGS[i]:
n_vocab=10, sot=0, all_language_tokens=0..9, all_language_codes set
to the 10 codes. Unused ids (eot, translate, transcribe,
no_timestamps, no_speech, …) are clamped to 0 so nothing indexes out of
bounds.That takes the pair from ~37M to ~17M parameters. Quantization is applied after
pruning: dynamic, per-channel, MatMul only (MatMulConstBOnly). Conv
layers stay fp32 — dynamic int8 Conv isn't well supported and that's where most
of the encoder's accuracy lives. metadata_props is re-attached after
quantization, since ORT's quantizer drops it.
import sherpa_onnx
config = sherpa_onnx.SpokenLanguageIdentificationConfig(
whisper=sherpa_onnx.SpokenLanguageIdentificationWhisperConfig(
encoder="tiny-encoder.int8.onnx",
decoder="tiny-decoder.int8.onnx",
),
num_threads=1,
provider="cpu",
)
slid = sherpa_onnx.SpokenLanguageIdentification(config)
s = slid.create_stream()
samples, sample_rate = sherpa_onnx.read_wave("test.wav") # 16 kHz mono
s.accept_waveform(sample_rate, samples)
print(slid.compute(s)) # -> 'he'
Plain onnxruntime works too. Run the encoder, then one decoder step with
tokens=[[0]] (sot is remapped to 0) and zeroed self-attention caches; softmax
over the 10 logits. See check_lid.py in the source repo.
he; Whisper's older exports call it iw. Both are accepted by the
pruning script, the metadata emits he.MIT, following openai/whisper-tiny.
3 commits