mlboydaisuke commited on
Commit
39993cd
Β·
verified Β·
1 Parent(s): b581455

decoder-transformer CPU placement (Mali audio quality) + clean Pixel samples: README.md

Browse files
Files changed (1) hide show
  1. README.md +25 -17
README.md CHANGED
@@ -16,14 +16,14 @@ tags:
16
  # Pocket-TTS-LiteRT
17
 
18
  [Pocket TTS](https://huggingface.co/kyutai/pocket-tts) (Kyutai, ~100M params) converted to
19
- **LiteRT `CompiledModel` graphs that run fully on a phone GPU**. Four stateless graphs +
20
- host-side orchestration reproduce the reference `pocket_tts` pipeline; on a Snapdragon
21
- phone the whole thing β€” language model, flow head and Mimi decoder β€” runs on the GPU at
22
- several times real-time.
23
 
24
  ![hero](assets/hero.png)
25
 
26
- Real output from the phone (nothing cloud, nothing post-processed):
27
 
28
  | voice | sample |
29
  |---|---|
@@ -42,7 +42,7 @@ draw into the next latent (LSD, 1 step); a 20M tiny Mimi (Γ—16 ConvTranspose ups
42
  | `pt_flowlm_fused` | emb[1,1,1024] + cos/sin + mask[1,16,1,513] + packed KV [1,96,512,64] + noise[1,32] β†’ [1,12321] = eos ∣ latent ∣ new-k ∣ new-v | one full AR frame (step + flow head) in one invocation with one readback β€” the variant the Android sample runs; on Mali the per-frame cost is dispatch/sync-bound, and fusing removes one invocation + three readbacks per frame |
43
  | `pt_flowlm_step` | emb[1,1,1024] + cos/sin + mask[1,16,1,513] + packed KV [1,96,512,64] β†’ cond, eos, new k/v | one AR step; KV cache lives on the host (split reference variant) |
44
  | `pt_flow_head` | cond[1,1024] + noise[1,32] β†’ latent[1,32] | LSD time embeddings (s=0, t=1) baked into the cond bias (split reference variant) |
45
- | `pt_mimi_dec_tx` | lat[1,65,32] β†’ feat[1,512,1024] | Mimi decoder transformer in 64-frame blocks (32-frame overlap: the 2-layer sliding-window attention has a 498-position stacked receptive field) |
46
  | `pt_mimi_deconly` | feat[1,512,4096] β†’ audio[1,1,491520] | SEANet decoder, one-shot 256-frame window (causal β‡’ exact per frame) |
47
 
48
  Host side (a few hundred lines of Kotlin/Python, no FFT anywhere): sentencepiece unigram
@@ -53,17 +53,25 @@ The `pt_voice_*.bin` files are Kyutai's published per-voice prompt states repack
53
  packed-KV layout (fp16). Text is chunked at ≀50 tokens along sentence boundaries, exactly
54
  like the reference implementation.
55
 
56
- ## Measured on device
57
-
58
- LiteRT 2.1.6, fp16 graphs, every graph fully delegated (`LITERT_CL`, zero CPU fallback
59
- nodes), decode after generation (no streaming), app process warm:
60
-
61
- * Samsung SM-S942Q (Snapdragon SM8850, Adreno): 8.2 s of speech in 1.63 s β€” **5.0Γ—
62
- real-time** (42-token single chunk, alba); 13.0 s in 3.05 s β€” **4.3Γ—** (3 chunks,
63
- marius). Measured with the split step+head graphs.
64
- * Pixel 8a (Tensor G3, Mali-G715): 7.9 s in 7.7 s β€” **~1.0Γ— real-time** (alba); 12.5 s in
65
- 13.1 s (3 chunks, marius). Measured with `pt_flowlm_fused`; the gap to Adreno is
66
- per-step overhead (25 MB packed-KV upload + kernel dispatch), not arithmetic.
 
 
 
 
 
 
 
 
67
 
68
  Numbers move with device, thermals and text length; treat them as one measured point, not
69
  a benchmark.
 
16
  # Pocket-TTS-LiteRT
17
 
18
  [Pocket TTS](https://huggingface.co/kyutai/pocket-tts) (Kyutai, ~100M params) converted to
19
+ **LiteRT `CompiledModel` graphs for the phone GPU**. Stateless graphs + host-side
20
+ orchestration reproduce the reference `pocket_tts` pipeline: the 100M language model, the
21
+ flow head and the SEANet vocoder run on the mobile GPU; the small 2-layer Mimi decoder
22
+ transformer runs on CPU (placement notes below).
23
 
24
  ![hero](assets/hero.png)
25
 
26
+ Real output from the phone (Pixel 8a, nothing cloud, nothing post-processed):
27
 
28
  | voice | sample |
29
  |---|---|
 
42
  | `pt_flowlm_fused` | emb[1,1,1024] + cos/sin + mask[1,16,1,513] + packed KV [1,96,512,64] + noise[1,32] β†’ [1,12321] = eos ∣ latent ∣ new-k ∣ new-v | one full AR frame (step + flow head) in one invocation with one readback β€” the variant the Android sample runs; on Mali the per-frame cost is dispatch/sync-bound, and fusing removes one invocation + three readbacks per frame |
43
  | `pt_flowlm_step` | emb[1,1,1024] + cos/sin + mask[1,16,1,513] + packed KV [1,96,512,64] β†’ cond, eos, new k/v | one AR step; KV cache lives on the host (split reference variant) |
44
  | `pt_flow_head` | cond[1,1024] + noise[1,32] β†’ latent[1,32] | LSD time embeddings (s=0, t=1) baked into the cond bias (split reference variant) |
45
+ | `pt_mimi_dec_tx` | lat[1,65,32] β†’ feat[1,512,1024] | Mimi decoder transformer in 64-frame blocks (32-frame overlap: the 2-layer sliding-window attention has a 498-position stacked receptive field) β€” **runs on CPU in the shipped app** (see Placement) |
46
  | `pt_mimi_deconly` | feat[1,512,4096] β†’ audio[1,1,491520] | SEANet decoder, one-shot 256-frame window (causal β‡’ exact per frame) |
47
 
48
  Host side (a few hundred lines of Kotlin/Python, no FFT anywhere): sentencepiece unigram
 
53
  packed-KV layout (fp16). Text is chunked at ≀50 tokens along sentence boundaries, exactly
54
  like the reference implementation.
55
 
56
+ ## Placement and measured numbers
57
+
58
+ Every graph compiles fully on the GPU (`LITERT_CL`, zero CPU-fallback nodes) on both
59
+ devices tried. The **shipped placement still runs `pt_mimi_dec_tx` on CPU**: on a Pixel
60
+ 8a's Mali the GPU output of that one graph is audibly degraded (alba voicing HNR 0.9 dB
61
+ on GPU vs 2.8 dB on CPU β€” CPU matches the fp32 desktop reference exactly), and requesting
62
+ FP32 GPU precision does not recover it. This mirrors what the Mimi zoo module documents
63
+ for its own decoder transformer, so the same split ships here: heavy compute (LM, flow
64
+ head, SEANet) on GPU, the 2-layer decoder transformer on CPU. It is 7 small calls per
65
+ utterance β€” on the Pixel the whole pipeline goes 1.03Γ— β†’ 1.01Γ— real-time.
66
+
67
+ LiteRT 2.1.6, fp16 graphs, decode after generation (no streaming), app process warm:
68
+
69
+ * Pixel 8a (Tensor G3, Mali-G715), shipped placement: 8.8 s of speech in 8.75 s β€”
70
+ **~1.0Γ— real-time** (alba); per-step cost is KV upload + dispatch overhead, not
71
+ arithmetic.
72
+ * Samsung SM-S942Q (Snapdragon SM8850, Adreno), measured with the all-GPU placement and
73
+ the split step+head graphs: 8.2 s in 1.63 s β€” **5.0Γ— real-time**; 13.0 s in 3.05 s β€”
74
+ **4.3Γ—** (3 chunks). The decoder-transformer-on-CPU delta measured ~2% on the Pixel.
75
 
76
  Numbers move with device, thermals and text length; treat them as one measured point, not
77
  a benchmark.