EchoBharat models
Quantized ONNX models for EchoBharat, an offline multilingual voice transceiver for Android. Phones turn speech into text locally, send only the text across a Bluetooth LE mesh, and turn it back into speech on the other side.
Everything here is a derived redistribution of work by other people. Nothing in this repository was trained here. See Licensing before you use any of it — the files are not all under the same terms.
What is in this repository
| Path | Contents | Derived from |
|---|---|---|
<lang>/fastpitch-<lang>.int8.onnx |
FastPitch acoustic model | AI4Bharat Indic-TTS |
<lang>/hifigan-<lang>.int8.onnx |
HiFi-GAN vocoder | AI4Bharat Indic-TTS |
<lang>/fastpitch-<lang>.tokens.json |
symbol table, indexed by token id | AI4Bharat Indic-TTS |
<lang>/sample-<lang>.wav |
a sample utterance, for listening | generated here |
mt/<lang>/mt-*-encoder.int8.onnx |
IndicTrans2 encoder | AI4Bharat IndicTrans2 |
mt/<lang>/mt-*-decoder.int8.onnx |
IndicTrans2 decoder | AI4Bharat IndicTrans2 |
mt/<lang>/mt-*-bpe-{src,tgt}.tsv |
flattened BPE vocabulary | AI4Bharat IndicTrans2 |
mt/<lang>/mt-*-meta.json |
language-tag ids and vocab sizes | AI4Bharat IndicTrans2 |
Speech recognition is not hosted here. EchoBharat uses the Apache-2.0 IndicConformer
conversions published at
parismitaglobalsolutions/indicconformer-sherpa-onnx
and links to them directly. They are documented below because anyone assembling a full
voice pack needs all three pieces.
Graph contracts
Read off the exported graphs, not copied from upstream documentation.
Speech-to-text — IndicConformer (hosted elsewhere, listed for completeness)
input audio_signal [B, 80, T] float32 log-mel features
length [B] int64 valid frames per item
output logprobs [B, T/4, V] float32 V = 5633 for the released vocabularies
Features are NeMo-compatible: 25 ms window, 10 ms hop, 512-point FFT, 80 Slaney mel bins,
0.97 pre-emphasis, log, then per_feature normalisation. Subsampling factor is 4.
Decoding is greedy CTC, and the blank token <blk> lives inside the vocabulary at id
5632 rather than being appended after it — assuming the usual "blank is index V" produces
plausible-looking but wrong transcripts.
Text-to-speech — FastPitch + HiFi-GAN
fastpitch input text [1, T] int64 token ids from the .tokens.json table
output mel [1, 80, F] float32
hifigan input mel [1, 80, F] float32
output audio [1, 1, S] float32 22050 Hz, mono, roughly [-1, 1]
Both are int8 dynamically quantized, weights only. The token axis and frame axis are dynamic. The two stages are exported separately rather than fused, so the vocoder — the expensive half — can be swapped or requantized on its own.
Tokenisation is longest-match against the symbol table in fastpitch-<lang>.tokens.json,
where the first id wins on duplicates.
Exporter note. FastPitch must be exported with PyTorch's dynamo exporter. Its
fftransformerencoder is built ontorch.nn.MultiheadAttention, which bakes the traced sequence length into aReshapeunder the legacy TorchScript tracer. The result loads without complaint and then fails at runtime on any sentence that is not exactly the dummy length:input_shape_size == requested_shape_size was false … requested shape:{24,1,512}.
Translation — IndicTrans2 (distilled 200M)
encoder input input_ids [B, S] int64
attention_mask [B, S] int64
output last_hidden_state [B, S, 512] float32
decoder input input_ids [B, T] int64
encoder_attention_mask [B, S] int64
encoder_hidden_states [B, S, 512] float32
output logits [B, T, V] float32
present.* (72 KV-cache tensors)
decoder_start_token_id = 2, which is also </s>. pad = 1, bos = 0, unk = 3.
Maximum source length is 256 tokens. The decoder here is the cacheless variant, so a
greedy loop re-runs the whole prefix each step; the 72 present.* outputs are ignored.
Using decoder_with_past_model.onnx instead is the obvious speed-up.
The source sequence is [<src_lang_tag>, <tgt_lang_tag>, …bpe pieces, </s>].
Two traps worth stating plainly:
- The SentencePiece piece ids and the ONNX graph vocabulary ids are different.
Upstream ships a
.modelfile and a separatedict.*.json; conflating the two produces fluent nonsense rather than an error. Thebpe-*.tsvfiles here are the two joined together —piece <TAB> score <TAB> graph_id— so this cannot be got wrong. Agraph_idof-1means the piece exists in SentencePiece but not in the graph vocabulary and must resolve to<unk>. - The FLORES language-tag ids differ per direction:
hin_Devais8going Indic→English and15going English→Indic. Hardcoding either value silently corrupts the other direction. They ship inmt-*-meta.json.
Which translation direction goes on which phone
EchoBharat translates on receive, never on send. A sender transmits in its own language and tags the packet with that language; each receiving phone translates into whatever language it is set to. That is what lets one broadcast reach a Hindi speaker and an English speaker simultaneously, each hearing their own — a sender that translated first would have to pick one target and the broadcast would stop being multilingual.
The consequence for packaging: a phone needs only the direction into its own language.
| Phone's language | Needs | Files | Size |
|---|---|---|---|
| English | Hindi → English | mt/en/mt-hi-en-* |
226 MB |
| Hindi | English → Hindi | mt/hi/mt-en-hi-* |
270 MB |
So an English handset carries mt/en/ and nothing else; it never needs mt/hi/.
Translation is available for Hindi ↔ English only. The other languages have speech-to-text and text-to-speech but no translation pair, and the app reports that honestly rather than passing text through as though it had been translated.
Licensing
These files are not all under one license. Redistributing them means honouring each upstream's terms separately.
| Component | Upstream | Upstream license | Notes |
|---|---|---|---|
| FastPitch / HiFi-GAN weights | AI4Bharat/Indic-TTS | MIT | checkpoints from the v1-checkpoints-release GitHub release |
| IndicTrans2 weights | ai4bharat/indictrans2-* | MIT | via the ONNX conversion below |
| IndicTrans2 ONNX conversion | TigreGotico/indictrans2-*-dist-200M-onnx | MIT | conversion this repo re-quantized/repacked |
| IndicConformer weights (linked, not hosted) | ai4bharat/indicconformer_stt_* | MIT | |
| IndicConformer ONNX conversion (linked, not hosted) | parismitaglobalsolutions/indicconformer-sherpa-onnx | Apache-2.0 | the conversion declares Apache-2.0 even though the upstream weights are MIT; honour both |
| Silero VAD (shipped in the app, not here) | snakers4/silero-vad | MIT | |
| Export and packaging scripts | this project | MIT |
The repository is marked license: other because a single SPDX identifier would
misrepresent at least one of the components above.
No new training data was used, and no new model was trained. Every weight here is a quantized re-export of a published checkpoint. Attribution belongs to AI4Bharat and to the authors of the conversions named above.
Known limitations
- Quantization is lossy. All models are int8. Quality is below the fp32 originals; how far below has not been measured against a reference.
- Odia is absent. No IndicConformer speech-to-text export exists for it, so a voice pack would be incomplete in the one direction that matters most.
- Translation has no KV cache, so decoding cost grows with the square of the output length.
- No IndicNLP normalisation in the translation path — NFKC only, unlike the reference IndicTrans2 pipeline. Unusual orthography is untested.
- Voice quality has not been formally evaluated. Each language ships a
sample-<lang>.wavprecisely so it can be listened to rather than taken on trust.
Citation
Please cite the upstream work rather than this repository.
@article{ai4bharat-indictrans2,
title = {IndicTrans2: Towards High-Quality and Accessible Machine Translation
Models for all 22 Scheduled Indian Languages},
author = {AI4Bharat},
journal = {Transactions on Machine Learning Research},
year = {2023}
}