ampixa
← all posts
// release · ratna

Ratna: small streaming Nepali speech recognition on a CPU

2026-11-09 · Ampixa Labs · 12 min read

Ratna is Ampixa's small streaming Nepali speech recognizer. It turns speech into text on a CPU while the speaker is still talking. The int8 bundle is 35.10 MB, with 31,963,576 parameters. It is intended for captions, voice typing and first-pass transcripts that a person can correct.

Illustration of a small crowned gem on a laptop transcribing Nepali speech.
While you speakLocal captions and voice typing need text while the speaker is still talking.

Why was it built?

Typing Nepali on a phone is slow. Speech recognition can turn a dictated message, lecture or voice note into editable text, but a large download and a remote transcription service are obstacles for local use. Ratna was built for applications that need to keep audio on the device and run on an ordinary CPU.

Small and streaming solve different parts of that problem. A small model can fit in a browser download or a local application. Streaming lets a person see a draft while speaking, so captions and voice typing do not have to wait for a recording to finish. Ratna targets that combination, accepting lower accuracy than larger Nepali recognizers.

How does it work?

Ratna is a transducer: an acoustic encoder represents the incoming speech, a predictor represents recently emitted tokens, and a joiner combines the two to choose the next token or a blank.

Audio · 16 kHz80-d log-mel10 ms hop · 100 HzConv2d50 Hz · d=16050 Hzd=1602 layers25 Hzd=1922 layers12.5 Hzd=2563 layers6.25 Hzd=3203 layers12.5 Hzd=2563 layers25 Hzd=1922 layersCausal Zipformer2 · six stacks · 15 layersCombine25 Hz · d=320Joiner · 512Predictor · embedding 512last 2 emitted tokensGreedy search2,048 BPE tokensTexttoken feedbackAudio · 16 kHz80-d log-mel filterbank10 ms hop · 100 HzConv2d subsampling50 Hz · d=1601 · 50 Hzd=160 · 2 layers2 · 25 Hzd=192 · 2 layers3 · 12.5 Hzd=256 · 3 layers4 · 6.25 Hzd=320 · 3 layers5 · 12.5 Hzd=256 · 3 layers6 · 25 Hzd=192 · 2 layersCausal Zipformer2 · 15 layersCombine25 Hz · d=320Joiner · 512Predictorembedding 512last 2 tokensGreedy search2,048 BPE tokensTexttokens
The six encoder stacks form a U in frame rate. d is the feature dimension; arrows follow the acoustic path and emitted-token feedback.

The frontend converts 16 kHz audio into an 80-dimensional log-mel filterbank every 10 ms, giving 100 frames per second. Conv2d subsampling reduces that to 50 Hz at dimension 160, cutting the sequence length before the encoder.

The causal Zipformer2 encoder has 15 layers across six stacks. It reduces the frame rate toward the middle of the U and raises it again toward the output. Slower stacks process fewer time steps, reducing computation. Each layer mixes attention, convolution and feed-forward blocks. The stacks have feed-forward dimensions 384 / 576 / 640 / 896 / 640 / 576, in the order drawn. A combine step produces 25 Hz features at dimension 320.

The predictor embeds the last two tokens at dimension 512. The 512-dimensional joiner combines that token context with the encoder output. Greedy search selects from 2,048 BPE tokens without beam search or an external language model. Emitted tokens feed back into the predictor. A 32-slot memory bank is present but empty in this release, so utterances are decoded independently.

One encoder stepLeft context · 128 frames2.56 sCurrent chunk16 frames320 msFuturenot usedDecode → partial textEach new chunk advances the window by 320 ms320 ms audio↓ text update320 ms audio↓ text update320 ms audio↓ text updateEncoder: no look-ahead into future chunksAt each encoder stepLeft context · 128 frames2.56 s of past audioCurrent chunk · 16 frames320 ms at 50 HzDecode → partial textNext chunk: shift and decode again320 msText update320 msText update320 msText updateEncoder: no look-aheadFuture chunks are not attended.
The encoder reuses past context and advances once per chunk. Text can update at each step; a step need not emit a new token. This is a schedule diagram, not a measured latency trace.

The streaming configuration advances 16 frames at 50 Hz, or 320 ms, with 128 frames of left context, or 2.56 s. The causal encoder has no look-ahead into future chunks. The frozen benchmark additionally reports 130 ms of frontend lookahead, so the complete recognizer should not be interpreted as having zero input delay.

For deployment, the encoder, predictor and joiner are exported to ONNX and quantized from float to int8. The model payload goes from 112.97 MiB to 33.43 MiB; the int8 ONNX files plus token table form the 35.10 MB release bundle. Inference uses sherpa-onnx on CPU or WebAssembly. MiB is binary; MB is decimal.

How was it tested?

The frozen comparison includes Ratna, AI4Bharat and AI-Lab IndicConformer, our earlier streaming model, MMS-1B, Omnilingual CTC 1B v2 and 300M v2, community wav2vec2 and Whisper, SeamlessM4T v2, and Whisper small, medium, large-v3 and large-v3-turbo. Each model is decoded separately on the same recordings for each panel, with fixed settings and the same scorer. There is no ensemble or selection of the best transcript per clip.

The panels separate recording conditions and reference quality:

  • PV bench: 100 real read-speech recordings from four speakers, paired with their reference sentences.
  • Fresh: 96 real natural-speech clips from twelve voices in public videos. References are machine-drafted and corrected, rather than gold human transcripts.
  • FLEURS: the public Nepali read-speech test, 726 sentences, using its dataset references.
  • Phone-band: synthetic copies of PV and Fresh resampled 16 → 8 → 16 kHz. This measures bandwidth loss; it does not reproduce a real telephone channel.
  • Degraded: separate synthetic copies with band limitation, noise and clipping.
  • Exact entities: 132 real Nepali customer-service phone calls, evaluated against reference entities for complete phone numbers, amounts, spelled codes and emails. Capture is recall under a ±1 s matching rule; it does not measure precision.
  • NepTel 0.2: a supplementary real-phone-audio evaluation with the public dataset's corrected reference key.
  • Public PVSpeech half: a supplementary evaluation of the 50 public clips from two speakers, using their references. It is a subset of PV, rather than an independent panel.

Ratna was trained with public and synthetic speech, including machine-generated labels. Label provenance is incomplete for part of that material, making this a research release. It was not trained on real call audio. The frozen text-overlap screen found one PV transcript and 23 Fresh transcripts in Ratna's training or development text. Exposure of comparison models to the evaluation material is not established.

Character error rate (CER) counts substitutions, deletions and insertions divided by reference characters; word error rate (WER) does the same over words. Both are computed over corpus totals. The legacy scorer includes normalized spaces in CER and uses normalized whitespace tokens for WER. Its fixed loanword rule transliterates a hypothesis containing Latin characters only when the reference contains none, before the shared normalization. NepTel 0.2 and the public PV half use the newer NepTel normalization, so their scores are kept separate from the frozen legacy results.

Frozen accuracy intervals use 10,000 bootstrap resamples at 95% confidence, grouped by speaker for PV and Fresh and by sentence for FLEURS. Paired comparisons use the same draws for both systems. These are pointwise intervals without a multiple-comparison adjustment. Four PV speakers give limited population evidence; FLEURS sentence resampling does not establish speaker independence.

Ratna runs int8 streaming greedy search. Comparators retain their standard float32 inference configurations and fixed decoding settings; Whisper uses fixed Nepali, transcription mode, greedy search and 30-second windows. The published community Whisper configuration fails loading; its repaired configuration is a separate supplementary result.

How fast is it?

Real-time factor, RTF, is decoding wall time divided by audio duration. Below 1.0, decoding takes less time than the recording lasts. Ratna's frozen 0.0273 RTF corresponds to 27.29 ms of decoding per second of audio. It measures processing work, not the delay until a person sees text.

The model comparison uses one CPU thread, batch one, on an Apple M2 Ultra. The common speed sample contains 16 speaker-balanced clips, totalling 104.263 seconds per pass. The protocol excludes model loading, warmup and audio I/O/resampling, and includes frontend feature extraction. Qualified timings use the median of three warm passes, with a fresh process per model. Ratna is the only streaming path exercised in this table; other rows measure offline decoding.

ModelCPU1 RTFFile / bundle MBPeak RAM MiB
Ratna, int80.027335.10205.1
AI4Bharat IndicConformer0.0382523.192,720.2
AI-Lab IndicConformer0.0400513.522,787.0
MMS-1B*0.24083,868.808,261.3
Omnilingual 1B v20.20493,902.9611,604.7
Omnilingual 300M v20.10361,304.074,173.2
Community wav2vec2*0.10151,262.203,356.6
Whisper small0.7935967.002,257.1
Whisper large-v3-turbo1.23701,617.825,619.3

The file column gives the required checkpoint container or release bundle, excluding runtime libraries; comparator tokenizer/configuration overhead is separate. Peak RAM is the observed whole-process high-water mark, including runtime, loading and temporary transport/deserialization buffers. It is neither steady-state deployment memory nor memory per stream. Comparator int8 exports and optimized alternative engines were not measured.

MMS-1B ran alongside other decode activity. Community wav2vec2 was not qualified under the three-pass isolated-speed protocol. These two rows are descriptive.

CPU1 RTF · lower is fasterRatna0.0273AI4Bharat IndicConformer0.0382AI-Lab IndicConformer0.0400MMS-1B*0.2408Omnilingual 1B v20.2049Omnilingual 300M v20.1036Community wav2vec2*0.1015Whisper small0.7935Whisper large-v3-turbo1.2370RTF 1.0CPU1 RTF · lower is fasterRatna0.0273AI4Bharat IndicConformer0.0382AI-Lab IndicConformer0.0400MMS-1B*0.2408Omnilingual 1B v20.2049Omnilingual 300M v20.1036Community wav2vec2*0.1015Whisper small0.7935Whisper large-v3-turbo1.2370RTF 1.0
One linear RTF scale. The dotted line marks real time. *MMS and community wav2vec2 timings are descriptive; their qualification limits are stated above.

For Ratna, the 95% conditional input-composition interval for RTF is [0.0271, 0.0274], based on 10,000 paired resamples of the observed PV/Fresh groups. This describes variation in the fixed speed sample's composition, not device, scheduler or timing-noise uncertainty.

The separate portability test used the same 48-second clip, one configured inference thread, one excluded full warmup and three measured runs per device. These are means and three-run ranges, so they are not interchangeable with the frozen benchmark medians above.

DeviceRuntimeMean RTF [range]Peak RAM MiB
Apple M2 Ultra, macOSsherpa-onnx 1.13.80.0372 [0.0369, 0.0374]282.91
Intel Core i5-10400, Linuxsherpa-onnx 1.13.80.0489 [0.0485, 0.0494]139.40
AMD Ryzen 5 5600H, Windowssherpa-onnx 1.13.80.0533 [0.0526, 0.0538]139.49
Apple M2 Ultra, Chromesherpa-onnx 1.12.33, WASM SIMD0.0842 [0.0826, 0.0854]2,479.50, browser family*

Native timing covers waveform acceptance, frontend and decoding. Browser timing sums waveform acceptance, decoding/readiness and raw-result collection, excluding DOM rendering, playback and yields. Both include a 300 ms zero-tail flush and exclude loading/resampling, initialization and artificial real-time waits. Shared-machine load was uncontrolled. Each device repeated its own final transcript exactly; outputs can differ between platforms and runtime versions.

Browser RAM is the sampled sum of Chrome-family RSS, including helpers. Shared mappings may be counted twice and short peaks missed; it is not comparable to the native process peaks. WebAssembly linear memory was separately 512 MiB, which is not total browser RAM. A phone and Raspberry Pi have not been measured.

A separate first-partial probe used 24 clips, 80 ms waveform feeds, one Apple M2 Ultra CPU thread and no real-time pacing. The first nonempty partial appeared after a median 0.64 s of accumulated audio, with 1.44 s at the 95th percentile. Compute elapsed to that partial was a median 13.29 ms, with 35.08 ms at the 95th percentile. Initial silence is included in the audio clock. These clocks are reported separately; end-to-end speech-to-screen and endpoint latency were not measured.

How does Ratna compare on natural speech?

On Fresh, Ratna scores below Whisper-large-v3 in CER and close to omni-300m v2 and MMS. The paired confidence intervals for those latter comparisons include zero, so the test does not establish an accuracy difference.

Fresh CER %, lower is betterRatna27.15omni-300m v226.64MMS29.11Whisper-large-v368.89Fresh CER %, lower is betterRatna27.15omni-300m v226.64MMS29.11Whisper-large-v368.89
Natural speech, frozen legacy scorer. Bars use the same scale. Paired intervals do not establish a difference between Ratna and omni-300m v2 or MMS.

CER can exceed 100.00% when a model inserts enough words that were not spoken. These results describe the fixed decoding settings used in the benchmark.

Where Ratna loses: how much accuracy does it give up?

ModelPV CER %Fresh CER %FLEURS CER %
Ratna16.3327.1528.03
AI4Bharat IndicConformer9.9415.447.43
Ampixa earlier streaming model12.6817.7823.74
omni-1b v27.8520.609.01

These are CER percentages under the frozen legacy scorer. Ratna trails the larger Nepali models on read speech and natural speech. Under the degraded-audio control its CER rises to 69.48% on PV and 68.00% on Fresh.

The exact-entity test is a separate failure. Across 132 real Nepali customer-service phone calls, Ratna captures 0 of 298 phone numbers, 23 of 152 amounts, and 0 of 123 full emails. It should not be used alone to capture critical identifiers.

What happens on NepTel 0.2 phone audio?

NepTel 0.2 contains 78 segments and 2,647 reference words of real Nepali phone audio. Ratna decodes as the audio arrives, using the same streaming int8 greedy setup. The two other models below decode the whole clip offline. All three use the same reference key and scorer.

ModelNepTel 0.2 WER %
Rani33.51
AI4Bharat IndicConformer47.60
Ratna67.32

Ratna's paired WER gap to Rani is +33.79 percentage points, with a 95% interval of [+30.97, +36.58].

What does the public PVSpeech half show?

The public PVSpeech dataset contains 50 clips from two speakers. With NepTel 0.2 normalization, Ratna scores 18.87% CER and 43.09% WER.

EvaluationCER %WER %
Public PVSpeech half, NepTel 0.2 normalization18.8743.09
Full PV bench, frozen legacy scorer16.3339.26

The full 100-sentence PV bench remains 16.33% CER and 39.26% WER under the frozen legacy scorer. Both the evaluated recordings and normalization differ, so the two rows do not measure a change in model quality.

Where can I use it?

The measured trade-off suits local captions, voice typing and first-pass transcripts that a person can correct. The accuracy and entity results above determine whether that trade-off is acceptable for a particular application.

Try it on the Ratna page. The model files are on Hugging Face.

How can I use it?

Ratna is released under a simple condition. If you use it, distill it, train or evaluate on its outputs, or build on it, name it properly: Ratna (Ampixa Labs), in your model card or documentation. Anyone you pass it to keeps that credit.

Where can I check the public evaluations?

The public PVSpeech recordings and NepTel dataset provide public evaluation audio. The supplementary score receipt records the NepTel 0.2 and public PV-half scores and their normalization. The private exact-entity evaluation releases aggregate counts only.