mobilebytesensei's picture
correct peak RSS: it scales with utterance length, not a constant
7f50eb3 verified
|
Raw
History Blame Contribute Delete
5.72 kB
---
license: mit
library_name: sherpa-onnx
tags:
- automatic-speech-recognition
- indic
- onnx
- sherpa-onnx
- nemo
language:
- gu
- pa
- bn
- mr
- ml
- te
- ta
- kn
---
# Betterflow β€” IndicConformer CTC, ONNX int8 (8 Indic languages)
ONNX int8 exports of **AI4Bharat's per-language IndicConformer** hybrid CTC/RNNT checkpoints,
prepared for on-device offline ASR through `sherpa-onnx`'s `OfflineRecognizer.from_nemo_ctc`.
**These are derived artefacts. We are not the authors of the weights.**
## Provenance and licence
| | |
|---|---|
| Upstream | `ai4bharat/indicconformer_stt_<lang>_hybrid_ctc_rnnt_large` |
| Upstream licence | **MIT** (verified on each source model card, not inferred) |
| This repo's licence | **MIT**, inherited |
| What changed | CTC head exported to ONNX; dynamic int8 quantization; sherpa metadata stamped |
| What did NOT change | the weights themselves β€” no fine-tuning, no distillation |
Each language directory carries `export-meta.json` with the **sha256 of the source `.nemo`**, so
provenance is checkable rather than asserted.
Please cite AI4Bharat for the underlying models.
## Contents
Eight languages: `gu` `pa` `bn` `mr` `ml` `te` `ta` `kn`.
```
<lang>/model.int8.onnx 140,337,395 B (identical size across languages, DISTINCT weights)
<lang>/tokens.txt 67,605 B 5,633 entries
<lang>/export-meta.json source sha256, checksums, export settings
```
### int8 sha256 β€” all eight distinct
| lang | sha256 (first 16) | lang | sha256 (first 16) |
|---|---|---|---|
| `gu` | `9f8031996be1a4d7` | `ml` | `81c172f6ee3796f5` |
| `pa` | `1ad447f477040bbb` | `te` | `b0b3d335f2505ecd` |
| `bn` | `8b1bd509bb36ba86` | `ta` | `08b85596996429e1` |
| `mr` | `af22de1897679e4a` | `kn` | `16d950f36cfdb01e` |
The eight files are byte-identical **in size** because they share an architecture. They are
**different models** β€” the checksums above are the check that matters.
## ⚠️ Two things that will silently break this
**1. `normalize_type` must be `per_feature`.** It is stamped on every graph. If it is stripped or
set to `""`, the model **loads, runs, and returns EMPTY with no error**. Verify by decoding, never
by a successful load.
Required ONNX metadata: `vocab_size=5633`, `subsampling_factor=4`,
`normalize_type=per_feature`, `feature_dim=80`.
**2. `tokens.txt` opens with Bengali tokens in every language directory β€” this is correct.** The
vocabulary is AI4Bharat's shared 22-language tokenizer (5,633 = 22 Γ— 256 + 1) and the CTC head is
multi-softmax. It looks like a packaging error and is not. The file is byte-identical across all
eight (`ee60967630213f31…`); it is duplicated per directory so each bundle installs independently.
Unlike the 600m multilingual checkpoint, these per-language models **did** learn to suppress the
other 21 blocks β€” measured 100% own-script output on all eight, 0/400 wrong-alphabet characters β€”
so **no `language_id` masking is required**.
## Measured quality
Scored on held-out `ARTPARK-IISc/Vaani`, 50 clips Γ— 50 speakers per language, against the
general-purpose multilingual Whisper bundle these replace.
| lang | incumbent pooled WER | **this export** | script purity | catastrophic |
|---|---|---|---|---|
| `pa` | 106.2% | **20.2%** | 0% β†’ **100%** | 13 β†’ **0** |
| `gu` | 106.6% | **22.6%** | 0% β†’ **100%** | 16 β†’ **0** |
| `bn` | 135.1% | **30.6%** | 0% β†’ **100%** | 21 β†’ **0** |
| `mr` | 100.5% | **36.6%** | 83% β†’ **100%** | 14 β†’ **0** |
| `ml` | 111.9% | **37.2%** | 0% β†’ **100%** | 16 β†’ **1** |
| `te` | 115.5% | **45.0%** | 6% β†’ **100%** | 8 β†’ **1** |
| `ta` | 87.0% | **52.1%** | 100% β†’ **100%** | 3 β†’ **1** |
| `kn` | 100.3% | **59.5%** | 100% β†’ **100%** | 2 β†’ **1** |
**Script purity is the headline, not WER.** A 0% score means the incumbent was not producing the
language's alphabet at all. Catastrophic failures fell from **93/400 to 5/400**.
`te` and `kn` remain insertion-bound and are **not** recommended without further evaluation.
## Runtime cost
### ⚠️ Peak RSS scales with utterance length β€” it is not a constant
Conformer self-attention is **O(TΒ²)** in sequence length, so memory is a function of how long the
speaker talks. Measured in-process (Android arm64, sherpa-onnx 1.13.4, int8, 2 threads, one process
per utterance, Β±1 MB reproducible):
| utterance | peak RSS | | utterance | peak RSS |
|---|---|---|---|---|
| 5 s | **285 MB** | | 45 s | 868 MB |
| 10 s | **350 MB** | | 60 s | 986 MB |
| 20 s | **482 MB** | | 90 s | 1,628 MB |
| 30 s | 606 MB | | 134 s | **2,758 MB** |
**Budget accordingly**: a typical 3–10 s dictation utterance costs under 350 MB, but a two-minute
monologue costs 2.7 GB. If you have a memory ceiling, cap utterance length β€” that is the cheapest
control and it belongs in your app, not in the model.
| | |
|---|---|
| RTF | 0.062–0.064 (~16Γ— real time on an M4 laptop) |
| RTF, 2Γ— ARM Cortex-A55 @1.25 GHz | **1.33** (~13 s for a 10 s utterance) |
| RTF, 4Γ— Cortex-A78 | **0.255** |
The int8 build quantizes **all 54 `Conv` nodes** to `ConvInteger`. Leaving them in fp32 β€” as some
other re-exports do β€” makes ONNX Runtime allocate an im2col workspace that scales with clip length,
pushing peak RSS to **2,099–2,635 MB** from the same nominal precision. If you are getting 4Γ— the
memory you expect from an int8 Conformer, check your `Conv` node dtypes.
Cost of that choice: `ConvInteger` is ~3.6Γ— slower than fp32 `Conv` on CPU.
## Not evaluated here
Device-side accuracy, languages outside the eight, streaming/partial decoding (these are **offline**
models), and the RNNT head (not exported β€” it needs numba/CUDA).