Update model card with LiteRT-LM Omni (.litertlm) documentation

#5
Files changed (1) hide show
  1. README.md +285 -47
README.md CHANGED
@@ -1,60 +1,254 @@
1
  ---
2
  license: mit
3
- library_name: litert
4
- base_model:
5
- - UsefulSensors/moonshine-tiny
6
- base_model_relation: quantized
7
  pipeline_tag: automatic-speech-recognition
 
 
 
 
8
  tags:
9
- - audio
10
- - automatic-speech-recognition
11
- - litert
12
- - tflite
 
 
 
 
 
 
 
 
13
  ---
14
 
15
- # Moonshine Tiny — LiteRT
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- [Moonshine Tiny](https://huggingface.co/UsefulSensors/moonshine-tiny) is a
18
- 27M-parameter encoder-decoder speech-recognition model from Moonshine AI
19
- (formerly Useful Sensors), introduced in
20
- [Moonshine: Speech Recognition for Live Transcription and Voice Commands](https://arxiv.org/abs/2410.15608).
21
- It transcribes English speech and is designed for fast on-device inference.
 
22
 
23
- This repository packages the model for [LiteRT](https://ai.google.dev/edge/litert):
24
- a float32 model, an int8 model (dynamic-range-quantized decoder with a
25
- float32 encoder), and ahead-of-time compiled variants for a range of MediaTek
26
- and Qualcomm SoCs so the model can run on the device NPU.
27
 
28
- ## Model description
 
 
 
 
 
 
29
 
30
- Each `.tflite` file contains two signatures that together form the
31
- transcription loop:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  | Signature | Inputs | Output |
34
  |---|---|---|
35
  | `encode` | raw audio `[1, 80000]` float32 (5 s at 16 kHz, zero-padded) | encoder states `[1, 207, 288]` float32 |
36
  | `decode` | states `[1, 207, 288]`, tokens `[1, 64]` int32, additive causal mask `[1, 1, 64, 64]` float32 | logits `[1, 64, 32768]` float32 |
37
 
38
- - The audio frontend is inside the graph: the model takes a raw 16 kHz
39
- waveform in `[-1, 1]` — no mel-spectrogram extraction is needed.
40
- - The window is fixed at 5 seconds. Longer audio is transcribed in
41
- consecutive 5 s windows; shorter audio is zero-padded.
42
- - Decoding is greedy: start token `1`, EOS token `2`, at most 64 tokens per
43
- window. The decoder re-scores the full token buffer each step (no KV
44
- cache), so decode time grows with the number of emitted tokens.
45
- - The tokenizer is not duplicated in this repository — load `tokenizer.json`
46
- from the base model repository (see the script below).
 
47
 
48
- ### Files
49
-
50
- | File | Description |
51
- |---|---|
52
- | `moonshine_tiny_5s_f32.tflite` | float32 model (109 MB) |
53
- | `moonshine_tiny_5s_i8.tflite` | int8 model (52 MB): float32 encoder + dynamic-range int8 decoder |
54
- | `moonshine_tiny_5s_f32_MediaTek_*.tflite` | float32 AOT-compiled for MediaTek NPUs (per SoC) |
55
- | `moonshine_tiny_5s_f32_Qualcomm_*.tflite` | float32 AOT-compiled for Qualcomm NPUs (per SoC) |
56
-
57
- ## How to use
58
 
59
  **1. Install dependencies**
60
 
@@ -178,11 +372,11 @@ python transcribe.py --wav sample.wav
178
 
179
  ### Android sample app
180
 
181
- For an on-device Android demo that runs Moonshine (and other ASR models) with
182
- hardware acceleration, see the LiteRT
183
  [speech recognition sample](https://github.com/google-ai-edge/litert-samples/tree/main/samples/litert/speech_recognition).
184
 
185
- ## Performance
186
 
187
  Measured on one 5 s window of continuous speech (11 output tokens), CPU
188
  inference, median of 10 runs. The macOS and Raspberry Pi rows use the Python
@@ -244,11 +438,55 @@ For the source model's quality, the
244
  Tiny matches Whisper tiny.en word error rates across standard evaluation
245
  datasets at about 5x less compute.
246
 
247
- ## License and attribution
248
 
249
- The original Moonshine Tiny model is released by Moonshine AI under the MIT
250
- license; these converted artifacts inherit it. If you use this model, please
251
- cite:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
 
253
  ```bibtex
254
  @misc{jeffries2024moonshinespeechrecognitionlive,
 
1
  ---
2
  license: mit
3
+ library_name: litert-lm
 
 
 
4
  pipeline_tag: automatic-speech-recognition
5
+ base_model: UsefulSensors/moonshine-tiny
6
+ base_model_relation: quantized
7
+ language:
8
+ - en
9
  tags:
10
+ - litert
11
+ - litert-lm
12
+ - tflite
13
+ - asr
14
+ - automatic-speech-recognition
15
+ - speech-to-text
16
+ - on-device
17
+ - android
18
+ - ios
19
+ - moonshine
20
+ - int8
21
+ - npu
22
  ---
23
 
24
+ # Moonshine-Tiny for LiteRT-LM
25
+
26
+ Ultra-lightweight (~30 MB), fully on-device English speech-to-text in a single
27
+ file.
28
+
29
+ This is
30
+ [UsefulSensors/moonshine-tiny](https://huggingface.co/UsefulSensors/moonshine-tiny)
31
+ (27M-parameter encoder-decoder speech recognition transformer from Moonshine AI,
32
+ formerly Useful Sensors, introduced in
33
+ [Moonshine: Speech Recognition for Live Transcription and Voice Commands](https://arxiv.org/abs/2410.15608))
34
+ packaged as a self-contained `.litertlm` bundle for
35
+ [LiteRT-LM Omni](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni),
36
+ Google's open-source on-device inference runtime across Android, iOS, macOS,
37
+ Linux, and C++, alongside standalone `.tflite` and AOT-compiled NPU variants for
38
+ [LiteRT](https://github.com/google-ai-edge/LiteRT). Everything needed to
39
+ transcribe English speech with punctuation and capitalization is inside the one
40
+ `.litertlm` file: INT8 encoder-decoder transformer with an in-graph raw-waveform
41
+ convolutional front-end, 32,768-token Hugging Face BPE tokenizer, and
42
+ `Speech2TextMetadata` — no Python and no network required.
43
+
44
+ - **Languages:** English (`en`) with automatic punctuation and capitalization
45
+ - **Footprint:** **29.7 MB** `.litertlm` bundle (smallest speech-to-text model
46
+ in LiteRT-LM Omni)
47
+ - **Audio front-end:** Raw 16 kHz waveform input (`[1, 80000]` float32 per 5 s
48
+ window) — the convolutional audio stem is built directly into the TFLite
49
+ `encode` graph, so no external STFT or mel-spectrogram computation is needed
50
+ - **Streaming:** 5-second sliding windows with configurable overlap
51
+ (`overlap_ratio` of `0.4` to `0.75`) and cross-window seam alignment for
52
+ arbitrary-length audio
53
+
54
+ ## Which file should I use?
55
+
56
+ | File | Size | Backend | Recommended for |
57
+ |---|---:|---|---|
58
+ | **`moonshine_tiny_5s_i8.litertlm`** ⭐ | 29.7 MB | CPU / GPU (`--backend=cpu` recommended) | **[LiteRT-LM Omni](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni) (`OmniEngine` / `omni_runner`) across Android, iOS, macOS, Linux, and C++.** All-in-one `.litertlm` bundle with INT8 encoder-decoder model, bundled 32,768-token tokenizer, and `Speech2TextMetadata`. |
59
+ | `moonshine_tiny_5s_i8.tflite` | 51.9 MB | CPU | Standalone [LiteRT](https://ai.google.dev/edge/litert) `.tflite` model (FP32 encoder + dynamic-range INT8 decoder; see [Standalone `.tflite` usage](#standalone-tflite-usage-python-litert) below). |
60
+ | `moonshine_tiny_5s_f32.tflite` | 109 MB | CPU / GPU | Unquantized FP32 standalone `.tflite` model (`encode` and `decode` signatures). |
61
+ | `moonshine_tiny_5s_f32_<SoC>.tflite` | 77–102 MB | NPU + CPU | Standalone LiteRT NPU pipelines AOT-compiled for a specific mobile SoC (see below). |
62
+
63
+ How the variants differ:
64
+
65
+ - **`.litertlm` vs. `.tflite`** — the `.litertlm` file bundles the `.tflite`
66
+ graph together with the compressed Hugging Face `tokenizer.json` and
67
+ `Speech2TextMetadata` protobuf in one self-contained archive for
68
+ [LiteRT-LM Omni](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni)'s
69
+ `OmniEngine` and `omni_runner`. Standalone `.tflite` files contain only the
70
+ neural network graph and require loading `tokenizer.json` from the upstream
71
+ repository.
72
+ - **AOT-compiled NPU `.tflite` files (`_<SoC>.tflite`)** — pre-compiled for
73
+ on-device NPU accelerators via the LiteRT NeuroPilot / QNN compilers:
74
+
75
+ | SoC family | Available `<SoC>` suffixes |
76
+ |---|---|
77
+ | **Qualcomm Snapdragon** | `Qualcomm_SM8450` (8 Gen 1), `SM8550` (8 Gen 2), `SM8650` (8 Gen 3), `SM8750` (8 Elite), `SM8850` (8 Elite Gen 5), `SA8255`, `SA8295` |
78
+ | **MediaTek Dimensity** | `MediaTek_MT6877`, `MT6878`, `MT6879`, `MT6897`, `MT6983` (9000), `MT6985` (9200), `MT6989` (9300), `MT6991` (9400), `MT6993`, `MT8171`, `MT8188`, `MT8189` |
79
+
80
+ ## Download
81
+
82
+ ```sh
83
+ pip install -U huggingface_hub
84
+
85
+ # Recommended: INT8 .litertlm bundle (29.7 MB, English)
86
+ hf download litert-community/moonshine-tiny \
87
+ moonshine_tiny_5s_i8.litertlm --local-dir .
88
+ ```
89
+
90
+ ---
91
+
92
+ ## Usage with LiteRT-LM Omni (`omni_runner` & C++)
93
+
94
+ All commands below accept mono or multi-channel WAV files at any sample rate
95
+ (automatically resampled to 16 kHz mono) and stream confirmed and unconfirmed
96
+ transcript segments to stdout (or `--output_path`). Prerequisites (Bazel,
97
+ Android NDK) are in the LiteRT-LM
98
+ [build guide](https://github.com/google-ai-edge/LiteRT-LM/blob/main/docs/getting-started/build-and-run.md)
99
+ and the
100
+ [LiteRT-LM Omni documentation](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni).
101
+
102
+ ### 1. Download a model
103
+
104
+ ```sh
105
+ pip install -U huggingface_hub
106
+ hf download litert-community/moonshine-tiny \
107
+ moonshine_tiny_5s_i8.litertlm --local-dir .
108
+ ```
109
+
110
+ > [!TIP]
111
+ > If you omit `--model_path` and pass `--model_name=moonshine-tiny`,
112
+ > `omni_runner` automatically downloads `moonshine_tiny_5s_i8.litertlm` into
113
+ > `--cache_dir` on first run.
114
+
115
+ ### 2. Build the runner
116
+
117
+ ```sh
118
+ git clone https://github.com/google-ai-edge/LiteRT-LM.git && cd LiteRT-LM
119
+ bazel build -c opt //omni:omni_runner # Linux / macOS
120
+ bazel build -c opt --config=android_arm64 //omni:omni_runner # Android (needs ANDROID_NDK_HOME)
121
+ ```
122
+
123
+ ### 3. Transcribe speech
124
+
125
+ **On Linux or macOS (CPU):**
126
+
127
+ ```sh
128
+ bazel-bin/omni/omni_runner --model_name=moonshine-tiny \
129
+ --model_path=/path/to/moonshine_tiny_5s_i8.litertlm \
130
+ --audio_path=runtime/components/testdata/audio_sample.wav
131
+ ```
132
+
133
+ **On an Android phone (CPU, recommended):**
134
+
135
+ ```sh
136
+ DEVICE_DIR=/data/local/tmp/omni
137
+ adb shell mkdir -p $DEVICE_DIR
138
+ adb push bazel-bin/omni/omni_runner prebuilt/android_arm64/*.so \
139
+ /path/to/moonshine_tiny_5s_i8.litertlm \
140
+ runtime/components/testdata/audio_sample.wav $DEVICE_DIR
141
 
142
+ adb shell LD_LIBRARY_PATH=$DEVICE_DIR $DEVICE_DIR/omni_runner \
143
+ --model_name=moonshine-tiny \
144
+ --backend=cpu --cache_dir=$DEVICE_DIR/cache \
145
+ --model_path=$DEVICE_DIR/moonshine_tiny_5s_i8.litertlm \
146
+ --audio_path=$DEVICE_DIR/audio_sample.wav
147
+ ```
148
 
149
+ **On an Android phone (GPU):**
 
 
 
150
 
151
+ ```sh
152
+ adb shell LD_LIBRARY_PATH=$DEVICE_DIR $DEVICE_DIR/omni_runner \
153
+ --model_name=moonshine-tiny \
154
+ --backend=gpu --cache_dir=$DEVICE_DIR/cache \
155
+ --model_path=$DEVICE_DIR/moonshine_tiny_5s_i8.litertlm \
156
+ --audio_path=$DEVICE_DIR/audio_sample.wav
157
+ ```
158
 
159
+ > `--model_name=moonshine-tiny` (or alias `moonshine`) tells the runner which
160
+ > model family the file is (it is inferred automatically when the file is named
161
+ > `moonshine-tiny.litertlm`). XNNPACK weight packs and compiled GPU kernels are
162
+ > cached in `--cache_dir` so subsequent runs start fast.
163
+
164
+ The full list of flags and the C++ `OmniEngine` / `OmniSession` streaming API
165
+ are documented in the
166
+ [LiteRT-LM Omni README](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni).
167
+
168
+ ### Use from C++ (`OmniEngine`)
169
+
170
+ ```cpp
171
+ #include "omni/omni_engine.h"
172
+ #include "omni/omni_session.h"
173
+ #include "runtime/proto/speech2text_session_config.pb.h"
174
+
175
+ using ::litert::omni::OmniEngine;
176
+ using ::litert::omni::OmniSession;
177
+ using ::litert::omni::PushInputSource;
178
+
179
+ OmniEngine::Settings settings{
180
+ .backend = OmniEngine::Settings::Backend::kCpu,
181
+ .cache_dir = "/data/local/tmp/omni/cache",
182
+ .model_path = "/data/local/tmp/omni/moonshine_tiny_5s_i8.litertlm",
183
+ };
184
+ litert::lm::proto::Speech2TextSessionConfig asr_config;
185
+ asr_config.set_overlap_ratio(0.4f);
186
+
187
+ ABSL_ASSIGN_OR_RETURN(
188
+ auto engine,
189
+ OmniEngine::Create("moonshine-tiny", settings, &asr_config));
190
+ auto input_source = std::make_unique<PushInputSource>();
191
+ PushInputSource* input = input_source.get();
192
+ ABSL_ASSIGN_OR_RETURN(auto session,
193
+ engine->CreateSession(std::move(input_source)));
194
+
195
+ // Push input audio metadata once, followed by one or more PCM float chunks.
196
+ ABSL_RETURN_IF_ERROR(input->PushInput(
197
+ OmniSession::AudioInputMetadata{.sample_rate_hz = 16000, .num_channels = 1}));
198
+ ABSL_RETURN_IF_ERROR(input->PushInput(
199
+ OmniSession::AudioInput{.pcm_samples = std::move(pcm_chunk)}));
200
+ input->Finish();
201
+ // Pull OmniSession::TextOutput updates (confirmed_text + unconfirmed_text)
202
+ // with session->ProcessNext() until OutOfRange or NotFound, then call session->Flush().
203
+ ```
204
+
205
+ In your `BUILD` file, link only the Moonshine target
206
+ (`//omni/speech2text:moonshine`) to avoid pulling in other speech, TTS, or image
207
+ generation models:
208
+
209
+ ```python
210
+ cc_binary(
211
+ name = "my_asr_app",
212
+ srcs = ["my_asr_app.cc"],
213
+ deps = [
214
+ "//omni:omni_engine",
215
+ "//omni:omni_session",
216
+ "//omni/speech2text:moonshine",
217
+ ],
218
+ )
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Standalone `.tflite` Usage (Python LiteRT)
224
+
225
+ If you are using the standalone `.tflite` files (`moonshine_tiny_5s_f32.tflite`
226
+ or `moonshine_tiny_5s_i8.tflite`) directly with the Python
227
+ [LiteRT](https://ai.google.dev/edge/litert) `CompiledModel` API instead of
228
+ LiteRT-LM Omni:
229
+
230
+ ### Model signatures
231
+
232
+ Each `.tflite` file contains two signatures that together form the transcription
233
+ loop:
234
 
235
  | Signature | Inputs | Output |
236
  |---|---|---|
237
  | `encode` | raw audio `[1, 80000]` float32 (5 s at 16 kHz, zero-padded) | encoder states `[1, 207, 288]` float32 |
238
  | `decode` | states `[1, 207, 288]`, tokens `[1, 64]` int32, additive causal mask `[1, 1, 64, 64]` float32 | logits `[1, 64, 32768]` float32 |
239
 
240
+ - The audio frontend is inside the graph: the model takes a raw 16 kHz
241
+ waveform in `[-1, 1]` — no mel-spectrogram extraction is needed.
242
+ - The window is fixed at 5 seconds. Longer audio is transcribed in consecutive
243
+ 5 s windows; shorter audio is zero-padded.
244
+ - Decoding is greedy: start token `1`, EOS token `2`, at most 64 tokens per
245
+ window. The decoder re-scores the full token buffer each step (no KV cache),
246
+ so decode time grows with the number of emitted tokens.
247
+ - When using the standalone `.tflite` files directly, load `tokenizer.json`
248
+ from the base model repository (`UsefulSensors/moonshine-tiny`), as shown
249
+ below (the `.litertlm` bundle already embeds `tokenizer.json`).
250
 
251
+ ### Run with Python `ai-edge-litert`
 
 
 
 
 
 
 
 
 
252
 
253
  **1. Install dependencies**
254
 
 
372
 
373
  ### Android sample app
374
 
375
+ For an on-device Android demo that runs standalone `.tflite` Moonshine models
376
+ with hardware acceleration, see the LiteRT
377
  [speech recognition sample](https://github.com/google-ai-edge/litert-samples/tree/main/samples/litert/speech_recognition).
378
 
379
+ ## Performance (Standalone `.tflite`)
380
 
381
  Measured on one 5 s window of continuous speech (11 output tokens), CPU
382
  inference, median of 10 runs. The macOS and Raspberry Pi rows use the Python
 
438
  Tiny matches Whisper tiny.en word error rates across standard evaluation
439
  datasets at about 5x less compute.
440
 
441
+ ## What's in the file
442
 
443
+ Inside `moonshine_tiny_5s_i8.litertlm`:
444
+
445
+ | Component | Details |
446
+ |---|---|
447
+ | **Audio front-end** | Self-contained C++ resampler + `DummyPreprocessor` (`Speech2TextMetadata`): resamples any input audio rate to 16 kHz mono and zero-pads short final chunks to 80,000 samples (5.0 s). The convolutional waveform front-end runs inside the TFLite `encode` graph. |
448
+ | **Encoder-decoder (`tf_lite_encoder_decoder`)** | 27M-parameter Moonshine Tiny transformer (`~29.1 MB`, INT8 weights) with two signatures: `encode` (raw waveform `[1, 80000]` float32 → encoder hidden states `[1, 207, 288]` float32) and `decode` (encoder states `[1, 207, 288]`, token IDs `[1, 64]` int32, additive causal mask `[1, 1, 64, 64]` float32 → logits `[1, 64, 32768]` float32). |
449
+ | **Decoder (`StatelessDecoder`)** | Greedy autoregressive decoding from start token `1` (`<s>`) until stop token `2` (`</s>`) or 64 tokens per 5 s window, with automatic trailing repetition truncation. |
450
+ | **Tokenizer (`HF_Tokenizer_Zlib`)** | Zlib-compressed Hugging Face `tokenizer.json` (32,768-token BPE vocabulary with punctuation and capitalization). |
451
+ | **Text merger** | Cross-window overlap seam alignment across consecutive 5 s windows (`overlap_ratio = 0.4` in `omni_runner`). |
452
+ | **Output** | Streaming `OmniSession::TextOutput` chunks (`confirmed_text` + `unconfirmed_text`). |
453
+
454
+ The models were exported from the upstream PyTorch checkpoint
455
+ (`UsefulSensors/moonshine-tiny`) with
456
+ [litert-torch](https://github.com/google-ai-edge/litert-torch) and quantized
457
+ with the AI Edge Quantizer. No retraining or fine-tuning was done.
458
+
459
+ ## Limitations
460
+
461
+ - **English only:** Moonshine Tiny is trained on English speech only. For
462
+ multilingual speech recognition, use
463
+ [`litert-community/parakeet-tdt-0.6b-v3`](https://huggingface.co/litert-community/parakeet-tdt-0.6b-v3)
464
+ (25 European languages),
465
+ [`litert-community/Qwen3-ASR-0.6B`](https://huggingface.co/litert-community/Qwen3-ASR-0.6B)
466
+ (52 languages and dialects), or
467
+ [`litert-community/whisper-tiny`](https://huggingface.co/litert-community/whisper-tiny)
468
+ (99 languages).
469
+ - **Fixed 5-second encoder window (max 64 tokens per window):** Longer audio
470
+ is processed in overlapping 5-second windows. Because `decode` re-evaluates
471
+ the 64-token buffer at each step without a stateful KV cache, `--backend=cpu`
472
+ is recommended for lowest end-to-end latency.
473
+ - **SoC-specific NPU files are standalone `.tflite` graphs:** The pre-compiled
474
+ `moonshine_tiny_5s_f32_<SoC>.tflite` files target the standalone LiteRT NPU
475
+ C++/Kotlin APIs rather than `.litertlm` bundles.
476
+
477
+ ## License & acknowledgements
478
+
479
+ - **Weights & tokenizer:** [MIT](https://opensource.org/licenses/MIT),
480
+ inherited from
481
+ [UsefulSensors/moonshine-tiny](https://huggingface.co/UsefulSensors/moonshine-tiny)
482
+ by Moonshine AI (formerly Useful Sensors).
483
+ - **Conversion & runtime:**
484
+ [litert-torch](https://github.com/google-ai-edge/litert-torch),
485
+ [LiteRT](https://github.com/google-ai-edge/LiteRT), and
486
+ [LiteRT-LM Omni](https://github.com/google-ai-edge/LiteRT-LM/tree/main/omni)
487
+ (Apache-2.0).
488
+
489
+ If you use this model, please cite:
490
 
491
  ```bibtex
492
  @misc{jeffries2024moonshinespeechrecognitionlive,