iaratts-roadmap / PHASE3_PLAN.md
marcosremar2's picture
Upload folder using huggingface_hub
71c511c verified
|
Raw
History Blame Contribute Delete
9.36 kB
# Phase 3 Plan β€” Zero-GPU engineering wave
**Status:** planejado, nΓ£o iniciado
**Date drafted:** 2026-04-27 (revised)
**Pre-req:** Phase 2 SFT done (WER 0.5316 β†’ 0.1537, baseline β†’ SFT, commit `79e9489`)
**Source of truth:** [`IARATTS_ROADMAP.md`](./IARATTS_ROADMAP.md) Revision 4
**Total budget:** $0 GPU, 1 wall-week, single engineer
> **Note:** the original Phase 3 (instruction+tag SFT) was renamed to Phase 4.4 in roadmap Revision 2 β€” it requires a multilingual continued-pretrain (Phase 4.2) as prerequisite, so it moved later. The current Phase 3 is all zero-GPU engineering wins that ship before any backbone retraining.
---
## Goal
Address ~60–70% of user-visible MOSS-Nano weaknesses via wrapper / frontend / cache code, no architecture change, no GPU spend. Foundation for Phase 4 (continued pretrain) and Phase 5 (codec swap + streaming distillation).
---
## Sub-phases
### Phase 3.1 β€” pt-BR text frontend (W1)
**Recommended path:** Adopt **Gruut + `num2words(lang='pt_BR')` + small custom Brazil rules** β€” exactly what `Piper-pt_BR-edresson` already ships. End-to-end pt-BR support: G2P, number normalization, abbreviation expansion.
**Alternative:** Author pt-BR FSTs in WeTextProcessing-engine style (~50–100 rules). `wenet-e2e/WeTextProcessing` officially supports only zh/en/ja, so this is net-new authoring.
**Patches in MOSS-Nano source:**
- Replace `resolve_text_normalization_language()` to route by **voice β†’ language**, not by character set heuristic.
- Insert pt-BR pipeline branch between text input and tokenizer.
**Validation:** Amazon Polly pt-BR phoneme table is the gold standard.
**Effort:** S+ (2–4 days). **GPU:** $0.
---
### Phase 3.2 β€” Repetition-Aware Sampling (RAS, W3-decode)
**Top fix:** Lift RAS from VALL-E 2 (arXiv:2406.05370). Implementation already shipping in `FunAudioLLM/CosyVoice/cosyvoice/llm/llm.py` β€” copy-paste the function.
**Mechanism:** at each step compute repetition ratio of candidate token over a sliding window; if exceeds threshold Ο„, redraw from original distribution (instead of top-p restricted).
**Effect:** breaks infinite-loop pathology (issue #44 β€” same input loops 8Γ— one seed, 200Γ— another).
**Effort:** S (1 day). **GPU:** $0.
---
### Phase 3.3 β€” Sentence chunking + prompt re-injection (W3-decode + W4)
**Inference wrapper:**
- Cap `max_length` to 512 frames (~40s) per chunk.
- Re-inject the speaker prompt at every chunk boundary so AR doesn't drift.
- Hides ~80% of long-form failures pre-SFT.
**Effort:** S (1–2 days). **GPU:** $0.
---
### Phase 3.4 β€” Voice profile cache + reference normalization (W4)
**Layer:** Silero VAD + WavLM-base + IndexedDB.
**Mechanism:**
1. **Speaker-encoder cache:** WavLM-base (94M) runs once per voice, not per inference; cached 192-d embedding goes to IndexedDB keyed by file hash.
2. **Reference normalization:** trim leading/trailing silence (Silero VAD), peak-normalize to -23 LUFS, resample to model's native rate.
3. **API:** `cloneVoice(refWav) β†’ voiceId` and `tts(text, voiceId)`.
**Fixes issue-#9 ("MP3 doesn't work / 6s-30s all garbage") by enforcing 3–10s clean window.**
**Effort:** S (3–4 days). **GPU:** $0.
---
### Phase 3.5 β€” Bug fixes (RoPE NaN + ONNX truncation)
- **Issue #28:** RoPE `inv_freq` corruption when loading via `from_pretrained` causes NaN logits. Apply upstream patch or workaround.
- **Issue #32:** ONNX path drops trailing audio. Add stop-token explicit padding before ONNX export.
**Effort:** S (1 day). **GPU:** $0.
---
### Phase 3.6 β€” Meta Quest 15-viseme stream emission ⭐ NEW
**Goal:** alongside the audio stream, emit a viseme stream compatible with **Meta Quest avatar SDK** (15-viseme Oculus inventory: `sil, PP, FF, TH, DD, kk, CH, SS, nn, RR, aa, E, ih, oh, ou`). **Per-viseme `start_ms`/`end_ms` timing is the priority** β€” accept +5–15 ms TTFT cost for tight avatar lipsync.
**Architecture:**
1. **IPA→Oculus 15-viseme lookup table (pt-BR)** — full table in [`IARATTS_VISEMES_CONTINUITY.md`](./IARATTS_VISEMES_CONTINUITY.md).
2. **Source timing:** AR LM token timestamps Γ— phoneme duration model (Gruut/eSpeak-NG) β†’ start/end per viseme.
3. **Output schema (HeadTTS-compatible JSON):**
```json
{
"visemes": ["sil", "aa", "kk", "aa", "sil"],
"vtimes_ms": [0, 80, 160, 240, 380],
"vdurations_ms":[80, 80, 80, 140, 60],
"phonemes": ["_", "a", "k", "a", "_"]
}
```
4. **Optional:** 60 fps soft-weight stream `float[15]` per frame for Avatar SDK 2 / Movement SDK direct consumption.
**Reference impl:** [`met4citizen/HeadTTS`](https://github.com/met4citizen/HeadTTS) β€” Kokoro browser w/ visemes.
**Effort:** S+ (2–3 days). **GPU:** $0.
---
### Phase 3.7 β€” In-session style continuity hybrid ⭐ NEW
**Goal:** successive utterances in a session sound like the same person continuing to speak, not separate generations stitched together.
**3-layer cache (total <5 KB persistent per voice):**
| Layer | Content | Persistence | Size |
|---|---|---|---|
| **A β€” Speaker** | Spark-TTS BiCodec 32 tokens + StyleTTS-2 256-d style vector + WavLM 192-d | IndexedDB **forever** | ~1.5 KB |
| **B β€” Emotion + Prosody EMA** | rate, pitch_mean, pitch_std, energy + IndexTTS2 256-d emotion vector | sessionStorage | ~1 KB |
| **C β€” Audio-token tail** | Last 1.5 s = ~75 X-Codec 2 tokens, re-injected as F5-TTS-style prompt prefix at next utterance | rolling per-utterance | ~120 B |
**Inference flow:**
```
session start: load Layer A (IndexedDB) + Layer B (sessionStorage if exists, else neutral)
utterance N:
text + Layer A speaker_emb + Layer B emotion_EMA + Layer C audio_tail (1.5s previous)
↓ AR LM streaming (Phase 3.2 + 3.3)
↓ post: extract last 1.5s tokens β†’ Layer C update
↓ post: update Layer B EMA with measured rate/pitch_mean of utterance N
utterance N+1: same person continuing, no "stitched" feel
```
**Reference patterns:** F5-TTS reference encoding (Layer C); Spark-TTS BiCodec (Layer A); ElevenLabs/OpenAI session-continuity behavior (production reference).
**Effort:** S+ (3–4 days). **GPU:** $0.
---
## Acceptance criteria (Phase 3 exit)
| Test | Target | Source |
|---|---|---|
| pt-BR sentence frontend correctness (200 prompts: numbers, abbrev, dates, currency) | <5% WER vs ground-truth (Whisper-large-v3 round-trip) | Phase 3.1 |
| Infinite-loop bug repro (issue #44) | 0% loops in 50 attempts Γ— 5 seeds each | Phase 3.2 |
| Long-form drift on 50 paragraph-length prompts | <10% drop-rate (vs ~80% baseline) | Phase 3.3 |
| Voice clone at 3s/6s/10s/30s reference | WavLM-SV cosine β‰₯0.65 at 3s, β‰₯0.75 at 6s | Phase 3.4 |
| ONNX export round-trip | 0 trailing-audio cutoff in 100 random prompts | Phase 3.5 |
| Viseme stream timing accuracy | per-viseme start/end aligned within Β±20 ms vs forced-aligner ground truth | Phase 3.6 |
| Style continuity in 5-utterance session | A/B test: β‰₯70% of native raters say "sounds like the same person continuing" vs no-cache baseline | Phase 3.7 |
---
## Files to create when executing
- `iaratts/frontend/pt_br_pipeline.py` β€” Gruut + num2words + custom rules (Phase 3.1)
- `iaratts/inference/ras_sampler.py` β€” RAS wrapper around AR sampling (Phase 3.2)
- `iaratts/inference/chunked_decode.py` β€” sentence chunking + prompt re-injection (Phase 3.3)
- `iaratts/wrapper/voice_cache.ts` β€” IndexedDB voice profile cache + WavLM (Phase 3.4)
- `iaratts/patches/rope_nan_fix.py`, `iaratts/patches/onnx_truncation_fix.py` (Phase 3.5)
- `iaratts/avatar/oculus_viseme_emitter.py` — IPA→Oculus 15-viseme + timing extractor (Phase 3.6)
- `iaratts/avatar/ipa_to_oculus_pt_br.json` β€” pt-BR mapping table (Phase 3.6)
- `iaratts/wrapper/style_continuity.ts` β€” 3-layer hybrid cache (Phase 3.7)
- `iaratts/eval/phase3_acceptance.py` β€” automated acceptance suite
---
## What comes after Phase 3
Per [`IARATTS_ROADMAP.md`](./IARATTS_ROADMAP.md):
- **Phase 4** ($60–110 GPU): 48kβ†’24k vocoder retrain, continued pt-BR+EN bilingual pretrain, hybrid TF + EOS sub-loss SFT, **paralinguistic tag SFT (Bark recipe) + IndexTTS2 instruction LM** (this is what the original "Phase 3 plan" was).
- **Phase 5.x** ($80–150 GPU): X-Codec 2 codec swap (TTFT 20ms first-frame floor), DCAR chunk-AR, Spark-TTS attribute tokens.
- **Phase 5.5 + 5.5a/b/c** ($115–190 GPU): CosyVoice-2-style streaming AR distillation to 150M, Speech Speculative Decoding (1.4Γ—), Multi-Token Prediction 8 heads + Viterbi (4–5Γ—), SpeakStream interleaved text-speech training. **Target TTFT: 80–180 ms WebGPU M1.**
- **Phase 6** (last resort, $80–150): FM pivot if Phase 5.5 plateaus. Streaming lost.
- **Phase 7** (polish, $20–30): OpenVoice-v2 tone-color converter; Mamba/SSM/RWKV TTS if browser ONNX matures.
---
## Companion documents
- [`IARATTS_ROADMAP.md`](./IARATTS_ROADMAP.md) β€” full roadmap, Revision 4
- [`IARATTS_ROADMAP_VALIDATION.md`](./IARATTS_ROADMAP_VALIDATION.md) β€” independent EN+ZH validation
- [`IARATTS_TTFT_VALIDATION.md`](./IARATTS_TTFT_VALIDATION.md) β€” TTFT optimization research
- [`IARATTS_VISEMES_CONTINUITY.md`](./IARATTS_VISEMES_CONTINUITY.md) β€” visemes Meta Quest + 3-layer continuity
- [`MOSS_NANO_WEAKNESSES.md`](./MOSS_NANO_WEAKNESSES.md) β€” source weaknesses analysis
- [`PHASE2_SFT.md`](./PHASE2_SFT.md) β€” Phase 2 SFT report (WER -71%)