On-device Japanese speech recognition, fully on the mobile GPU.
nvidia/parakeet-tdt_ctc-0.6b-ja
(FastConformer hybrid TDT-CTC, 0.6B params, Japanese with punctuation) converted to LiteRT
.tflite for the CompiledModel API. The TDT (Token-and-Duration Transducer) branch is
exported as two signatures — encode (FastConformer encoder) and decode (LSTM prediction
network + joint) — the same layout the official
LiteRT speech recognition sample
uses for parakeet-tdt-0.6b-v3, so the sample's TdtDecoder runs it unchanged.
A 5 s window typically needs ~20 decode calls with the stateless loop, so f32 on the
Pixel 8a GPU transcribes 5 s of audio in roughly 2.1 s end-to-end. Both signatures
delegate fully (1862/1862 and 2083/2083 nodes on LITERT_CL).
⚠ Known limitation: the i8 variant fails to compile on Mali GPUs (Pixel 8a,
Unable to parse bc coord for BATCH axis in ML Drift OpenCL codegen, reproduced on
LiteRT 2.1.3 and 2.1.5). On the Pixel 8a the i8 model runs on CPU (verified,
numbers above). The f32 variant compiles and runs on the Pixel 8a GPU. Devices from
the official parakeet-tdt-0.6b-v3 validation list (Adreno / Tensor G5) use the same
graph layout and quant recipe. One Adreno device has since been measured here: on a
Galaxy S26 (Snapdragon 8 Elite Gen 5) the i8 files also fail to compile on the GPU,
while the f32 files run on that GPU — and on the Hexagon NPU after an ahead-of-time
compile. See Snapdragon NPU (Hexagon) below. Tensor G5 was not tested by this
conversion.
Conversion fidelity
Measured on a 137 s CC0 Japanese test read (日本国憲法前文, Wikimedia Commons),
processed as 28 × 5 s windows:
Reference quality of the base model (NeMo, from the
upstream card): CER 6.4 (JSUT
basic5000), 7.1 (Common Voice 8), 9.0 (TEDxJP-10K).
Stateful decoding (decode_1)
The _stateful files add a single-step decode_1 signature (LSTM states carried
between calls) next to a 4-token decode, the same layout as
parakeet-tdt-0.6b-v3's stateful files. Measured on the Pixel 8a GPU (f32):
compile 7.6 s, decode 16 ms, decode_18 ms per call — the 28-window sweep
that takes 18.2 s with the stateless file finishes in 3.0 s on a desktop CPU
(~6×), and a 5 s window on the Pixel 8a GPU drops from ~2.1 s to ~0.45 s of
decode+encode work.
Accuracy note: with correct RNN-T stateful semantics the f32 stateful file
reproduces NeMo transcribe()28/28 windows (CER 0.0000) — identical to the
stateless file. The TdtDecoder.kt shipped in the litert-samples app today has
two stateful-path defects (state adoption on blank steps; switching to
decode_1 one token early) that cost accuracy (16/28, CER 6.25% on the same
sweep); a fix is proposed in
litert-samples#278.
Until it merges, prefer the stateless files with the stock app, or apply the
two-line fix. (The minimal-usage snippet below uses the stateless file; for
stateful decoding, advance the LSTM states only on non-blank emissions and
fill the 4-token array before switching to decode_1.)
1import com.google.ai.edge.litert.Accelerator
2import com.google.ai.edge.litert.CompiledModel
34val model = CompiledModel.create(5 modelPath, CompiledModel.Options(Accelerator.GPU),null)67val encIn = model.createInputBuffers("encode")8val encOut = model.createOutputBuffers("encode")9encIn[0].writeFloat(logMel)// [1, 80, 500] as FloatArray(40000)10model.run(encIn, encOut,"encode")1112val decIn = model.createInputBuffers("decode")13val decOut = model.createOutputBuffers("decode")14val tokens =IntArray(64).also{ it[0]=3072}// blank start15// Greedy TDT loop: write tokens + zero LSTM states, run "decode",16// read [63, 64, 3078] logits, argmax tokens [0..3072] and durations17// [3073..3077] — identical to TdtDecoder.kt in the official18// litert-samples speech_recognition app, with blank id 3072.19decIn[1].writeInt(tokens)20decIn[2].writeFloat(FloatArray(2*640))21decIn[3].writeFloat(FloatArray(2*640))22model.run(listOf(encOut[0], decIn[1], decIn[2], decIn[3]), decOut,"decode")23val logits = decOut[0].readFloat()
Conversion
Converted with the official litert-samples
speech_recognition/convert
pipeline (litert-torch), through the ParakeetTDT path with the -ja model's constants
(vocab 3072, blank 3072, durations [0,1,2,3,4], 80 mel bins). The int8 variant uses the
pipeline's dynamic-range recipe (int8 channelwise weights, float32 activations).
Snapdragon NPU (Hexagon)
parakeet_tdt_ctc_0.6b_ja_5s_f32.tflite — the NPU is 2.10x faster than the GPU (30.33 ms against 63.61 ms) and loads 14.26x faster (420 ms against 5984 ms).
parakeet_tdt_ctc_0.6b_ja_5s_f32_stateful.tflite — the NPU is 2.08x faster than the GPU (30.32 ms against 63.03 ms) and loads 15.17x faster (394 ms against 5977 ms).
parakeet_tdt_ctc_0.6b_ja_5s_i8.tflite — neither accelerator produced a usable row on the S26. NPU: the ahead-of-time compile for SM8850 failed on the host. GPU: LiteRtException: Failed to compile model.
parakeet_tdt_ctc_0.6b_ja_5s_i8_stateful.tflite — neither accelerator produced a usable row on the S26. NPU: the ahead-of-time compile for SM8850 failed on the host. GPU: LiteRtException: Failed to compile model.
file
backend
compiled
inference (median / min)
load
parakeet_tdt_ctc_0.6b_ja_5s_f32.tflite
NPU (Hexagon v81)
AOT (SM8850)
30.33 ms / 29.87 ms
420 ms
parakeet_tdt_ctc_0.6b_ja_5s_f32.tflite
GPU (Adreno)
—
63.61 ms / 62.36 ms
5984 ms
parakeet_tdt_ctc_0.6b_ja_5s_f32_stateful.tflite
NPU (Hexagon v81)
AOT (SM8850)
30.32 ms / 29.90 ms
394 ms
parakeet_tdt_ctc_0.6b_ja_5s_f32_stateful.tflite
GPU (Adreno)
—
63.03 ms / 62.25 ms
5977 ms
Measured on a Samsung Galaxy S26 (Snapdragon 8 Elite Gen 5 / SM8850, Hexagon v81, Android 16) with LiteRT CompiledModel 2.2.0, one accelerator per process, 5 warm-up runs then N=50 timed runs, median reported. Every run held thermal status NONE throughout. Headroom 0.70–0.73, where 1.0 is the throttling threshold.
The NPU rows marked AOT ran an artifact compiled ahead of time for SM8850 (ai-edge-litert 2.2.0 + QAIRT 2.47.0), not the published file. That artifact is not distributed here; the compile is one command in the NPU guide.
Measured on a Raspberry Pi 5 Model B Rev 1.1 (8 GB, Raspberry Pi OS 64-bit) with the LiteRT benchmark_model tool from litert-cli-nightly 0.2.0.dev20260805: CPU inference (XNNPACK, 4 threads), 3 invocations per file of 10 warm-up plus 50 timed runs (the tool caps a phase at 150 s, so very slow graphs run fewer — the Runs column is the actual timed total). The latency is the median across invocations; the spread is the min–max over all timed runs. No thermal throttling occurred during these runs (vcgencmd get_throttled stayed 0x0).