Dynamic Accent Flash: add Flash-DPO (CosyVoice3) as --version flash (default), diacritic front-end, Flash results, samples
Browse files- .gitattributes +10 -0
- README.md +83 -22
- app.py +14 -11
- checkpoints/flash/diacritics_byt5/added_tokens.json +127 -0
- checkpoints/flash/diacritics_byt5/config.json +32 -0
- checkpoints/flash/diacritics_byt5/generation_config.json +7 -0
- checkpoints/flash/diacritics_byt5/model.safetensors +3 -0
- checkpoints/flash/diacritics_byt5/special_tokens_map.json +150 -0
- checkpoints/flash/diacritics_byt5/tokenizer_config.json +1163 -0
- checkpoints/flash/flash_dpo/args.json +1 -0
- checkpoints/flash/flash_dpo/best.pt +3 -0
- checkpoints/flash/flash_dpo/config.json +9 -0
- checkpoints/flash/flash_dpo/log.jsonl +31 -0
- checkpoints/flash/flash_dpo/spk2id.json +0 -0
- flash_lm.py +532 -0
- frontend/__init__.py +2 -0
- frontend/frontend.py +122 -0
- frontend/normalize.py +308 -0
- infer.py +101 -12
- prompts/flash_voices_text.json +3 -0
- samples/flash/codeswitch_dynacc.mp3 +0 -0
- samples/flash/codeswitch_ibo_pcm_eng.mp3 +3 -0
- samples/flash/codeswitch_yor_eng.mp3 +3 -0
- samples/flash/diacritics_yoruba_from_plain.mp3 +3 -0
- samples/flash/hausa_male.mp3 +3 -0
- samples/flash/igbo_para_female.mp3 +3 -0
- samples/flash/igbo_pure_female.mp3 +3 -0
- samples/flash/numbers_igbo.mp3 +3 -0
- samples/flash/pidgin_female.mp3 +3 -0
- samples/flash/yoruba_female.mp3 +3 -0
- samples/flash/yoruba_male.mp3 +3 -0
- settings.json +20 -2
.gitattributes
CHANGED
|
@@ -51,3 +51,13 @@ samples/phase3/phase3/para_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
|
| 51 |
samples/phase3/phase3/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 52 |
samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 53 |
samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
samples/phase3/phase3/para_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 52 |
samples/phase3/phase3_female/para_ibo_pcm_eng__waxal_ibo_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 53 |
samples/phase3/phase3_female/para_yor_eng__waxal_yor_5.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 54 |
+
samples/flash/codeswitch_ibo_pcm_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 55 |
+
samples/flash/codeswitch_yor_eng.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 56 |
+
samples/flash/diacritics_yoruba_from_plain.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 57 |
+
samples/flash/hausa_male.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 58 |
+
samples/flash/igbo_para_female.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 59 |
+
samples/flash/igbo_pure_female.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 60 |
+
samples/flash/numbers_igbo.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 61 |
+
samples/flash/pidgin_female.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 62 |
+
samples/flash/yoruba_female.mp3 filter=lfs diff=lfs merge=lfs -text
|
| 63 |
+
samples/flash/yoruba_male.mp3 filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
|
@@ -6,7 +6,9 @@ language:
|
|
| 6 |
- yo
|
| 7 |
- ig
|
| 8 |
- ha
|
| 9 |
-
base_model:
|
|
|
|
|
|
|
| 10 |
pipeline_tag: text-to-speech
|
| 11 |
library_name: pytorch
|
| 12 |
tags:
|
|
@@ -18,6 +20,8 @@ tags:
|
|
| 18 |
- hausa
|
| 19 |
- nigerian-pidgin
|
| 20 |
- cosyvoice2
|
|
|
|
|
|
|
| 21 |
datasets:
|
| 22 |
- google/WaxalNLP
|
| 23 |
- McGill-NLP/NaijaS2ST
|
|
@@ -32,7 +36,9 @@ datasets:
|
|
| 32 |
|
| 33 |
**Code-switching TTS for Nigerian languages.** English, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed freely inside one sentence and spoken by one consistent voice, with no model swapping between languages.
|
| 34 |
|
| 35 |
-
Dynamic Accent is
|
|
|
|
|
|
|
| 36 |
- per-token **language embeddings**, a **speaker token** and an adversarial (gradient-reversal) speaker classifier on the LM, so the voice stays the same across a language switch (after Zhang et al., Google, 2019, *Learning to Speak Fluently in a Foreign Language*);
|
| 37 |
- training on about 178 h of Nigerian-language and code-switched speech, including about 102 h of Igbo;
|
| 38 |
- learned `[pause]`/`[breath]` events and a speaking-rate instruction (Phase 3);
|
|
@@ -42,11 +48,12 @@ It is a research release, not a production system. Read **Limitations** before y
|
|
| 42 |
|
| 43 |
## Versions and voices
|
| 44 |
|
| 45 |
-
|
| 46 |
|
| 47 |
| version | LM | flow | decoding | what changed |
|
| 48 |
|---|---|---|---|---|
|
| 49 |
-
| `
|
|
|
|
| 50 |
| `phase2` | `checkpoints/phase2/p2_lm_B` (~120 h, pause profile B) | `checkpoints/phase2/p2_flow_sft` | sentence by sentence, internal silences capped at 0.6 s | the Phase 2 final system |
|
| 51 |
|
| 52 |
| voice (`--voice`) | who | notes |
|
|
@@ -55,7 +62,7 @@ Two model versions ship side by side. Pick one with `--version`, or render both
|
|
| 55 |
| `waxal_ibo_5_female` | WAXAL Igbo speaker 5, female, native Igbo | zero-shot (prompt clip, no fine-tune); best CER of the three on the female test subset |
|
| 56 |
| `waxal_yor_5_female` | WAXAL Yoruba speaker 5, female, native Yoruba | zero-shot; strongest identity match, but its 3.8 s prompt has no pauses, so pauses are short and endings often clipped |
|
| 57 |
|
| 58 |
-
**Recommended
|
| 59 |
|
| 60 |
## Setup (single GPU)
|
| 61 |
|
|
@@ -71,21 +78,25 @@ huggingface-cli download Modularcomputing/dynamic-accent-preview --local-dir dyn
|
|
| 71 |
pip install -r dynamic-accent-preview/requirements.txt
|
| 72 |
```
|
| 73 |
|
| 74 |
-
The stock base
|
| 75 |
|
| 76 |
## Usage
|
| 77 |
|
| 78 |
```bash
|
| 79 |
cd dynamic-accent-preview
|
| 80 |
-
# default: --version
|
| 81 |
python infer.py --cosyvoice_dir ../CosyVoice --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --out out.wav
|
| 82 |
|
| 83 |
-
#
|
| 84 |
-
python infer.py --cosyvoice_dir ../CosyVoice --version
|
| 85 |
--text "<ibo>Kedu ka ị mere?</ibo> <pcm>Abeg no vex, I go call you for evening.</pcm>" --out ibo_f.wav
|
| 86 |
|
| 87 |
-
#
|
| 88 |
-
python infer.py --cosyvoice_dir ../CosyVoice --
|
|
|
|
|
|
|
|
|
|
|
|
|
| 89 |
|
| 90 |
python infer.py --list_voices # voices, versions, recommended pairing
|
| 91 |
```
|
|
@@ -93,11 +104,16 @@ python infer.py --list_voices # voices, versions, recommended pairing
|
|
| 93 |
| flag | what it does |
|
| 94 |
|---|---|
|
| 95 |
| `--text` | the text: tagged (below) or plain with `--auto_tag` |
|
| 96 |
-
| `--version
|
| 97 |
| `--voice anchor_male\|waxal_ibo_5_female\|waxal_yor_5_female` | voice (default `anchor_male`); old ids `anchor`, `waxal_ibo_5`, `waxal_yor_5` still work |
|
| 98 |
| `--list_voices` | list voices, versions and the recommended pairing |
|
| 99 |
-
| `--compare` | render with
|
| 100 |
-
| `--
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
| `--auto_tag` | tag untagged mixed text automatically (see below), print the tagged text, then synthesise |
|
| 102 |
| `--tag_only` | with `--auto_tag`: print the tagged text and stop, so you can edit it and pass it back as `--text` |
|
| 103 |
| `--force_lang eng\|pcm\|ibo\|yor\|hau` | read the whole text in one language (tags are ignored) |
|
|
@@ -149,7 +165,7 @@ Write Yoruba and Igbo with their diacritics where you can; text without diacriti
|
|
| 149 |
python app.py --cosyvoice_dir ../CosyVoice # http://127.0.0.1:7860 (--share for a public link)
|
| 150 |
```
|
| 151 |
|
| 152 |
-
It has a text box, an auto-tag toggle with an editable tagged-text preview, word overrides, a force-language option, version, voice and rate dropdowns, a seed, and a **Compare** button that plays Phase
|
| 153 |
|
| 154 |
### From Python
|
| 155 |
|
|
@@ -158,13 +174,33 @@ import types, soundfile as sf, infer
|
|
| 158 |
a = types.SimpleNamespace(model_dir="pretrained/CosyVoice2-0.5B", cosyvoice_dir="../CosyVoice", lm="", flow="",
|
| 159 |
prompts="prompts/prompts.json", voices="prompts/voices.json", dtype="auto", stitch=False,
|
| 160 |
rate="default", voice="waxal_ibo_5_female")
|
| 161 |
-
tts = infer.build("phase3", a)
|
|
|
|
| 162 |
wav = tts.say("<ibo>Kedu ka ị mere?</ibo> <eng>The meeting has been moved to Friday morning.</eng>", seed=0)
|
| 163 |
sf.write("out.wav", wav, tts.sr)
|
| 164 |
```
|
| 165 |
|
| 166 |
## Samples
|
| 167 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 168 |
Seed 0, rendered with `infer.py`. Inputs: `para_ibo_pcm_eng`, `para_yor_eng`, `para_hau_eng_pcm` (code-switched paragraphs), `ibo_000` (Igbo), `custom_dynacc` ("this is dynamic accent, e dey sound nice abi?") and `omo_announce` ("omo, I'm very excited to announce this new model, ọ na-eme m obi ụtọ, I no go lie give you").
|
| 169 |
|
| 170 |
| input | Phase 2, anchor_male | Phase 3, anchor_male | Phase 3, female |
|
|
@@ -178,6 +214,24 @@ Seed 0, rendered with `infer.py`. Inputs: `para_ibo_pcm_eng`, `para_yor_eng`, `p
|
|
| 178 |
|
| 179 |
Older renders: `samples/pcm_eng_dynamic_accent_seed{0,1,2}.mp3` (Phase 2, three seeds) and `samples/prosody_v2/` (the rejected prosody-v2 post-processing, kept for reference).
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
## Evaluation: Phase 2 vs Phase 3
|
| 182 |
|
| 183 |
183-item eval set (30 per language, 10 code-switched, 3 hand-written + 20 native long-form paragraphs), anchor voice, seed 0. CER is ASR round-trip: MMS-1b-all for Igbo/Hausa/Yoruba, Whisper-large-v3-turbo for English and Pidgin, the lower of the two for code-switched items and paragraphs. "No tones" (in brackets) strips diacritics. SIM is ECAPA cosine to the anchor (ceiling about 0.84 on real held-out anchor clips). The Pidgin judge is weak: real Pidgin recordings score about 0.43.
|
|
@@ -221,7 +275,8 @@ On the held-out single-language set, per language (rule-based / + GlotLID): Engl
|
|
| 221 |
|
| 222 |
## Limitations
|
| 223 |
|
| 224 |
-
- **
|
|
|
|
| 225 |
- **Pidgin is the weakest language**: only about 5 h of training data, no reliable ASR judge, and the auto-tagger's Pidgin/English split is its weakest point (~0.63 word accuracy on plain Pidgin).
|
| 226 |
- **No laughter or other expressive events**: the training data has effectively no laughter, so tags like `[laughter]` do nothing useful. `[pause]`/`[breath]` were learned from data, but there is no reliable user control over them yet.
|
| 227 |
- English after a Nigerian-language span keeps a strong local accent.
|
|
@@ -234,13 +289,17 @@ On the held-out single-language set, per language (rule-based / + GlotLID): Engl
|
|
| 234 |
|
| 235 |
| path | what it is | licence |
|
| 236 |
|---|---|---|
|
|
|
|
|
|
|
| 237 |
| `checkpoints/phase3/p3_lm_full/` | Phase 3 LM (`best.pt`, val step 4,500), `config.json` (rate, sampler, one-pass, points at the shared Phase 2 flow), `spk2id.json`, `args.json`, `log.jsonl` | CC-BY-SA-4.0 |
|
| 238 |
| `checkpoints/phase2/p2_lm_B/` | Phase 2 LM (`best.pt`) and `spk2id.json` | CC-BY-SA-4.0 |
|
| 239 |
| `checkpoints/phase2/p2_flow_sft/best.pt` | anchor-SFT flow-matching decoder, used by both versions | CC-BY-SA-4.0 |
|
| 240 |
| `prompts/` | anchor prompt clips (`clip0..3`, `prompts.json` with transcripts and S3 tokens) and female voice prompts (`voice_*.wav`, `voices.json`), all from WAXAL | CC-BY-SA-4.0 |
|
| 241 |
-
| `samples/` | example renders | CC-BY-SA-4.0 |
|
| 242 |
| `settings.json` | versions, voices, recommended pairing | Apache-2.0 |
|
| 243 |
| `infer.py`, `tagger.py`, `app.py` | inference CLI, auto-tagger, Gradio app | Apache-2.0 |
|
|
|
|
|
|
|
| 244 |
| `code/` | the original training and synthesis code, for reference | Apache-2.0 |
|
| 245 |
| `requirements.txt`, `cosyvoice_requirements.txt` | dependencies (`cosyvoice_requirements.txt` is CosyVoice's own file at the commit used) | – |
|
| 246 |
| `assets/` | banner | – |
|
|
@@ -255,22 +314,24 @@ The model weights are trained on, and the voice prompts are taken from, the data
|
|
| 255 |
| [Open.Bible Igbo](https://huggingface.co/datasets/AfriSpeech/open-bible-speech-african) (Biblica® Open Igbo Contemporary Bible™, Audio Edition) | Igbo (Phase 3) | CC-BY-SA-4.0 | Biblica, Inc. via open.bible; Biblica® and Open Igbo Contemporary Bible™ are trademarks of Biblica, Inc. |
|
| 256 |
| [NaijaS2ST](https://huggingface.co/datasets/McGill-NLP/NaijaS2ST) (Igbo) | Igbo, many native speakers (Phase 3) | CC-BY-4.0 | McGill-NLP, NaijaS2ST (arXiv:2604.16287) |
|
| 257 |
| [IgboAPI](https://huggingface.co/datasets/nkowaokwu/ibo-dict) (ibo-dict, ibo-dict-expansion) | Igbo sentences (Phase 3) | CC-BY-4.0 | Nkọwa okwu / IgboAPI contributors |
|
| 258 |
-
| [IgboSynCorp](https://doi.org/10.7910/dvn/yb9fwk) | natural Igbo speech (Phase 3) | CC0-1.0 | University of Ibadan and Afe Babalola University (Lacuna Fund) |
|
| 259 |
| [FLEURS](https://huggingface.co/datasets/google/fleurs) (English, Hausa, Igbo, Yoruba) | multi-speaker data | CC-BY-4.0 | Google, FLEURS (Conneau et al., 2022) |
|
| 260 |
| [BibleTTS](https://masakhane-io.github.io/bibleTTS/) (Yoruba, Hausa) | Yoruba and Hausa | CC-BY-SA-4.0 | Meyer et al., BibleTTS (2022); Biblica / open.bible audio |
|
| 261 |
| [OpenSLR SLR70](https://openslr.org/70/) (Nigerian English) | English | CC-BY-SA-4.0 | Google, crowdsourced Nigerian English |
|
| 262 |
| [OpenSLR SLR86](https://openslr.org/86/) (Yoruba) | Yoruba | CC-BY-SA-4.0 | Google, crowdsourced Yoruba |
|
| 263 |
| code-switched pairs | about 9 h of synthetic code-switch training pairs | follows the source clips (CC-BY-SA-4.0 / CC-BY-4.0) | built by concatenating clips from the sets above, following the Google 2019 code-switching recipe (Zhang et al., 2019); no separate Google dataset |
|
|
|
|
|
|
|
| 264 |
| base model [FunAudioLLM/CosyVoice2-0.5B](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) | LM initialisation, flow, vocoder, tokenizers | Apache-2.0 | FunAudioLLM / Alibaba Tongyi Lab, CosyVoice 2 (Du et al., 2024) |
|
| 265 |
| optional [GlotLID](https://huggingface.co/cis-lmu/glotlid) (not bundled) | `--lid glotlid` in the tagger | Apache-2.0 plus notices | Kargaran et al., GlotLID (EMNLP 2023) |
|
| 266 |
|
| 267 |
-
Excluded on licence grounds: WaZoBiaSpeech (
|
| 268 |
|
| 269 |
## Licence
|
| 270 |
|
| 271 |
- **Model weights, voice prompts and samples** (`checkpoints/`, `prompts/`, `samples/`): **[CC-BY-SA-4.0](LICENSE)**. You may use them commercially. You must credit Modular and the datasets listed above, and anything you derive from the weights (fine-tunes, merges) must be shared under CC-BY-SA-4.0 too.
|
| 272 |
-
- **Code** (`infer.py`, `tagger.py`, `app.py`, `code/`, `settings.json`): **[Apache-2.0](LICENSE-CODE)**.
|
| 273 |
-
- The base
|
| 274 |
|
| 275 |
## Citation
|
| 276 |
|
|
|
|
| 6 |
- yo
|
| 7 |
- ig
|
| 8 |
- ha
|
| 9 |
+
base_model:
|
| 10 |
+
- FunAudioLLM/Fun-CosyVoice3-0.5B-2512
|
| 11 |
+
- FunAudioLLM/CosyVoice2-0.5B
|
| 12 |
pipeline_tag: text-to-speech
|
| 13 |
library_name: pytorch
|
| 14 |
tags:
|
|
|
|
| 20 |
- hausa
|
| 21 |
- nigerian-pidgin
|
| 22 |
- cosyvoice2
|
| 23 |
+
- cosyvoice3
|
| 24 |
+
- dpo
|
| 25 |
datasets:
|
| 26 |
- google/WaxalNLP
|
| 27 |
- McGill-NLP/NaijaS2ST
|
|
|
|
| 36 |
|
| 37 |
**Code-switching TTS for Nigerian languages.** English, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed freely inside one sentence and spoken by one consistent voice, with no model swapping between languages.
|
| 38 |
|
| 39 |
+
**New: Dynamic Accent Flash** (`--version flash`, now the default) is the same recipe ported to [FunAudioLLM/Fun-CosyVoice3-0.5B-2512](https://huggingface.co/FunAudioLLM/Fun-CosyVoice3-0.5B-2512), then preference-tuned with DPO for naturalness, intelligibility, pace and pauses, with a text front-end that restores Yoruba/Igbo diacritics. It is trained on licensed data only. See **Flash results** below.
|
| 40 |
+
|
| 41 |
+
Dynamic Accent (Phase 2/3) is a fine-tune of [FunAudioLLM/CosyVoice2-0.5B](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) by Modular. It adds:
|
| 42 |
- per-token **language embeddings**, a **speaker token** and an adversarial (gradient-reversal) speaker classifier on the LM, so the voice stays the same across a language switch (after Zhang et al., Google, 2019, *Learning to Speak Fluently in a Foreign Language*);
|
| 43 |
- training on about 178 h of Nigerian-language and code-switched speech, including about 102 h of Igbo;
|
| 44 |
- learned `[pause]`/`[breath]` events and a speaking-rate instruction (Phase 3);
|
|
|
|
| 48 |
|
| 49 |
## Versions and voices
|
| 50 |
|
| 51 |
+
Three model versions ship side by side. Pick one with `--version`, or render several with `--compare` and A/B before use.
|
| 52 |
|
| 53 |
| version | LM | flow | decoding | what changed |
|
| 54 |
|---|---|---|---|---|
|
| 55 |
+
| `flash` (**default**) | `checkpoints/flash/flash_dpo` on **Fun-CosyVoice3-0.5B-2512**: Flash SFT (CV3 LM, the Phase 3 data re-weighted towards natural speech, plus IgboSynCorp pseudo-transcripts) + DPO (1,206 preference pairs; reward = naturalness + CER + articulation rate + pause rate) | stock CV3 flow + vocoder, zero-shot from the voice clip | text front-end (numbers verbalised, missing Yoruba/Igbo diacritics restored by `checkpoints/flash/diacritics_byt5`), one pass per paragraph, silence-aware repetition check, no audio post-processing | pace about native, fewest clipped endings for every voice, lower anchor CER (see **Flash results**) |
|
| 56 |
+
| `phase3` | `checkpoints/phase3/p3_lm_full` (Phase 2 LM + 5,000 steps on a 178 h re-cut with ~102 h Igbo, `[pause]`/`[breath]` tags and a speed instruction, rate `normal`) | shared `checkpoints/phase2/p2_flow_sft` | one pass per paragraph, silence-aware repetition check, no audio post-processing | lower CER in Igbo/Hausa/Yoruba/code-switch/paragraphs, comma pauses at the anchor's length, clipped endings 63% → 11% |
|
| 57 |
| `phase2` | `checkpoints/phase2/p2_lm_B` (~120 h, pause profile B) | `checkpoints/phase2/p2_flow_sft` | sentence by sentence, internal silences capped at 0.6 s | the Phase 2 final system |
|
| 58 |
|
| 59 |
| voice (`--voice`) | who | notes |
|
|
|
|
| 62 |
| `waxal_ibo_5_female` | WAXAL Igbo speaker 5, female, native Igbo | zero-shot (prompt clip, no fine-tune); best CER of the three on the female test subset |
|
| 63 |
| `waxal_yor_5_female` | WAXAL Yoruba speaker 5, female, native Yoruba | zero-shot; strongest identity match, but its 3.8 s prompt has no pauses, so pauses are short and endings often clipped |
|
| 64 |
|
| 65 |
+
**Recommended:** `flash` with any of the three voices; it scores best overall (see **Flash results**), with one known weakness: with `anchor_male` it under-pauses in Igbo and Yoruba. Earlier listening verdict (before Flash): Phase 3 sounds best with the female voices, Phase 2 is fine for the male anchor. `infer.py` prints a note when you pick a pairing outside these. The female voices run with `phase2` but are untested there. Settings live in `settings.json`.
|
| 66 |
|
| 67 |
## Setup (single GPU)
|
| 68 |
|
|
|
|
| 78 |
pip install -r dynamic-accent-preview/requirements.txt
|
| 79 |
```
|
| 80 |
|
| 81 |
+
The stock base models download on first run and need no changes: `FunAudioLLM/Fun-CosyVoice3-0.5B-2512` to `pretrained/Fun-CosyVoice3-0.5B-2512` for `flash` (`--cv3_dir` / `CV3_DIR` to reuse a copy), and `FunAudioLLM/CosyVoice2-0.5B` to `pretrained/CosyVoice2-0.5B` for `phase2`/`phase3`. The same CosyVoice commit runs both (it has `CosyVoice3`). **`flash` needs a CUDA GPU** (tested on an H100, bf16). Point `--model_dir` (or `COSYVOICE2_DIR`) at an existing copy, and `--cosyvoice_dir` (or `COSYVOICE_REPO`) at your CosyVoice clone. A 16 GB GPU is enough for the CLI; the Gradio app keeps both versions loaded. Tested on an H100 (bf16). `infer.py` also runs on CPU in fp32, which is slow. T4-class GPUs fall back to fp16, which has not been tested.
|
| 82 |
|
| 83 |
## Usage
|
| 84 |
|
| 85 |
```bash
|
| 86 |
cd dynamic-accent-preview
|
| 87 |
+
# default: --version flash --voice anchor_male
|
| 88 |
python infer.py --cosyvoice_dir ../CosyVoice --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --out out.wav
|
| 89 |
|
| 90 |
+
# Flash with the female Igbo voice
|
| 91 |
+
python infer.py --cosyvoice_dir ../CosyVoice --version flash --voice waxal_ibo_5_female \
|
| 92 |
--text "<ibo>Kedu ka ị mere?</ibo> <pcm>Abeg no vex, I go call you for evening.</pcm>" --out ibo_f.wav
|
| 93 |
|
| 94 |
+
# plain Yoruba without tone marks: Flash's front-end restores them before synthesis
|
| 95 |
+
python infer.py --cosyvoice_dir ../CosyVoice --version flash --voice waxal_yor_5_female --frontend native --frontend_lang yor \
|
| 96 |
+
--text "E kaaaro, se daadaa ni gbogbo yin wa?" --out yor.wav
|
| 97 |
+
|
| 98 |
+
# A/B: the same text, seed and voice through several versions -> cmp_phase2.wav, cmp_phase3.wav, cmp_flash.wav
|
| 99 |
+
python infer.py --cosyvoice_dir ../CosyVoice --compare --compare_versions phase2,phase3,flash --voice anchor_male --text "..." --out cmp.wav
|
| 100 |
|
| 101 |
python infer.py --list_voices # voices, versions, recommended pairing
|
| 102 |
```
|
|
|
|
| 104 |
| flag | what it does |
|
| 105 |
|---|---|
|
| 106 |
| `--text` | the text: tagged (below) or plain with `--auto_tag` |
|
| 107 |
+
| `--version flash\|phase3\|phase2` | model version (default `flash`) |
|
| 108 |
| `--voice anchor_male\|waxal_ibo_5_female\|waxal_yor_5_female` | voice (default `anchor_male`); old ids `anchor`, `waxal_ibo_5`, `waxal_yor_5` still work |
|
| 109 |
| `--list_voices` | list voices, versions and the recommended pairing |
|
| 110 |
+
| `--compare`, `--compare_versions phase2,phase3,flash` | render with several versions → `<out>_<version>.wav` |
|
| 111 |
+
| `--frontend codeswitch\|native\|accent` | `flash` text front-end: `codeswitch` (default; tagged text, or untagged text in `--frontend_lang`), `native` (whole text in `--frontend_lang`, diacritics restored), `accent` (words as written, read with the `--frontend_lang` accent) |
|
| 112 |
+
| `--frontend_lang eng\|pcm\|ibo\|yor\|hau` | language for untagged text / `native` / `accent` |
|
| 113 |
+
| `--no_diacritics` | `flash`: do not restore missing Yoruba/Igbo tone marks and underdots |
|
| 114 |
+
| `--frontend translate --experimental_translate` | **experimental, off by default**: translate English/Pidgin into `--frontend_lang` (ibo/yor/hau) with MADLAD-400-3B-MT (Apache-2.0, ~12 GB download) before synthesis. MADLAD often loops (repeated words or dots) on longer inputs and translates Pidgin poorly, so check the printed text |
|
| 115 |
+
| `--cv3_dir` | `flash`: path of the Fun-CosyVoice3-0.5B-2512 snapshot |
|
| 116 |
+
| `--rate default\|none\|very slow\|slow\|normal\|fast\|very fast` | Phase 3 / Flash speaking-rate instruction to the LM (default: the version's setting, `normal`). It is a learned instruction, not time-stretching. `phase2` ignores it |
|
| 117 |
| `--auto_tag` | tag untagged mixed text automatically (see below), print the tagged text, then synthesise |
|
| 118 |
| `--tag_only` | with `--auto_tag`: print the tagged text and stop, so you can edit it and pass it back as `--text` |
|
| 119 |
| `--force_lang eng\|pcm\|ibo\|yor\|hau` | read the whole text in one language (tags are ignored) |
|
|
|
|
| 165 |
python app.py --cosyvoice_dir ../CosyVoice # http://127.0.0.1:7860 (--share for a public link)
|
| 166 |
```
|
| 167 |
|
| 168 |
+
It has a text box, an auto-tag toggle with an editable tagged-text preview, word overrides, a force-language option, version, voice and rate dropdowns, a seed, and a **Compare** button that plays Phase 3 and Flash side by side. The app launch has not been smoke-tested yet.
|
| 169 |
|
| 170 |
### From Python
|
| 171 |
|
|
|
|
| 174 |
a = types.SimpleNamespace(model_dir="pretrained/CosyVoice2-0.5B", cosyvoice_dir="../CosyVoice", lm="", flow="",
|
| 175 |
prompts="prompts/prompts.json", voices="prompts/voices.json", dtype="auto", stitch=False,
|
| 176 |
rate="default", voice="waxal_ibo_5_female")
|
| 177 |
+
tts = infer.build("phase3", a) # for "flash" also set frontend="codeswitch", frontend_lang="eng", no_diacritics=False,
|
| 178 |
+
# experimental_translate=False, cv3_dir="pretrained/Fun-CosyVoice3-0.5B-2512"
|
| 179 |
wav = tts.say("<ibo>Kedu ka ị mere?</ibo> <eng>The meeting has been moved to Friday morning.</eng>", seed=0)
|
| 180 |
sf.write("out.wav", wav, tts.sr)
|
| 181 |
```
|
| 182 |
|
| 183 |
## Samples
|
| 184 |
|
| 185 |
+
### Flash (`--version flash`, Flash-DPO)
|
| 186 |
+
|
| 187 |
+
Seed 0, model pauses, speed 1.0, no post-processing. Inputs are written with diacritics unless noted.
|
| 188 |
+
|
| 189 |
+
| sample | voice | text |
|
| 190 |
+
|---|---|---|
|
| 191 |
+
| [igbo_pure_female](samples/flash/igbo_pure_female.mp3) | waxal_ibo_5_female | Chei, obi dị m ụtọ nke ukwuu ịkpọsa ụdị ọhụrụ a, ọ na-eme m obi ụtọ, agaghị m agha gị ụgha. |
|
| 192 |
+
| [igbo_para_female](samples/flash/igbo_para_female.mp3) | waxal_ibo_5_female | Ndewo nu, ụmụnna m. Taa bụ ụbọchị pụrụ iche n'obodo anyị. Anyị ga-ezukọ n'ama egwuregwu, rie nri, ma kparịta ụka maka ọdịnihu ụmụaka anyị. |
|
| 193 |
+
| [yoruba_female](samples/flash/yoruba_female.mp3) / [yoruba_male](samples/flash/yoruba_male.mp3) | waxal_yor_5_female / anchor_male | Ẹ káàsán o, ẹ̀yin ará. Inú mi dùn láti rí gbogbo yín lónìí. Ẹ jẹ́ ká jọ ṣiṣẹ́ pọ̀ fún ìlọsíwájú ìlú wa. |
|
| 194 |
+
| [hausa_male](samples/flash/hausa_male.mp3) | anchor_male | Barka da yamma, 'yan uwa. Muna farin cikin ganin ku a yau. Za mu fara taron nan ba da daɗewa ba, don haka ku zauna lafiya. |
|
| 195 |
+
| [pidgin_female](samples/flash/pidgin_female.mp3) | waxal_ibo_5_female | Omo, this traffic no be here o. Abeg make una no vex, I go reach there small time. Wetin dey happen for your side? |
|
| 196 |
+
| [codeswitch_ibo_pcm_eng](samples/flash/codeswitch_ibo_pcm_eng.mp3) | waxal_ibo_5_female | `<ibo>Nne m, ọ dị mma, ka anyị gaa ahịa taa.</ibo> <pcm>Abeg make we no late o,</pcm> <eng>the shop closes at 6pm.</eng>` |
|
| 197 |
+
| [codeswitch_yor_eng](samples/flash/codeswitch_yor_eng.mp3) | waxal_yor_5_female | `<yor>Ẹ jọ̀ọ́, ẹ dúró díẹ̀,</yor> <eng>I will send you the report this afternoon.</eng> <yor>Ẹ ṣé púpọ̀.</yor>` |
|
| 198 |
+
| [codeswitch_dynacc](samples/flash/codeswitch_dynacc.mp3) | waxal_ibo_5_female | `<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>` |
|
| 199 |
+
| [numbers_igbo](samples/flash/numbers_igbo.mp3) | waxal_ibo_5_female | Ọnụ ahịa ya bụ ₦2,500, anyị ga-ahụ gị na 21/10/2026 n'elekere 4:30. (numbers verbalised by the front-end) |
|
| 200 |
+
| [diacritics_yoruba_from_plain](samples/flash/diacritics_yoruba_from_plain.mp3) | waxal_yor_5_female | input without marks: "E kaaaro, se daadaa ni gbogbo yin wa? Oju ojo dara pupo loni." → front-end: Ẹ káàárọ̀, ṣé dáadáa ni gbogbo yín wà? Ojú ọjọ́ dára púpọ̀ lónì. |
|
| 201 |
+
|
| 202 |
+
### Phase 2 and Phase 3
|
| 203 |
+
|
| 204 |
Seed 0, rendered with `infer.py`. Inputs: `para_ibo_pcm_eng`, `para_yor_eng`, `para_hau_eng_pcm` (code-switched paragraphs), `ibo_000` (Igbo), `custom_dynacc` ("this is dynamic accent, e dey sound nice abi?") and `omo_announce` ("omo, I'm very excited to announce this new model, ọ na-eme m obi ụtọ, I no go lie give you").
|
| 205 |
|
| 206 |
| input | Phase 2, anchor_male | Phase 3, anchor_male | Phase 3, female |
|
|
|
|
| 214 |
|
| 215 |
Older renders: `samples/pcm_eng_dynamic_accent_seed{0,1,2}.mp3` (Phase 2, three seeds) and `samples/prosody_v2/` (the rejected prosody-v2 post-processing, kept for reference).
|
| 216 |
|
| 217 |
+
## Flash results
|
| 218 |
+
|
| 219 |
+
Same eval set and judges as the Phase 2 vs Phase 3 tables below (183 items plus code-switched and paragraph groups), seed 0, all groups pooled. **Pace** and **pauses** are ratios to native speakers reading the same texts (1.00 = native). **Clipped endings** = share of renders whose trailing silence is under 0.1 s (native recordings: 23.8%). SIM is ECAPA cosine to the voice's own real clips.
|
| 220 |
+
|
| 221 |
+
| voice | system | CER | CER no tones | SIM | pace × native | pauses/s × native | clipped endings |
|
| 222 |
+
|---|---|---|---|---|---|---|---|
|
| 223 |
+
| anchor_male | Phase 3 | 0.174 | 0.146 | 0.815 | 0.92 | 1.11 | 9.1% |
|
| 224 |
+
| anchor_male | **Flash** | **0.162** | **0.135** | 0.784 | **0.99** | 0.75 | **7.1%** |
|
| 225 |
+
| waxal_ibo_5_female | Phase 3 | 0.164 | 0.132 | 0.683 | 1.00 | 0.74 | 22.8% |
|
| 226 |
+
| waxal_ibo_5_female | **Flash** | 0.165 | 0.134 | **0.700** | 1.03 | **0.95** | **10.7%** |
|
| 227 |
+
|
| 228 |
+
- Flash lowers the anchor's CER (0.174 → 0.162) and clipped endings (9.1% → 7.1%), brings its pace to about native (0.92× → 0.99×), and more than halves clipped endings on the female Igbo voice (22.8% → 10.7%) at about native pace and pause rate.
|
| 229 |
+
- Per language with the anchor, Flash CER: Igbo 0.189 (Phase 3: 0.210), Yoruba 0.230 (0.243), Hausa 0.123 (0.146), English 0.026 (0.039), paragraphs 0.131 (0.168), code-switch 0.208 (0.212); Pidgin 0.227 (0.209) is worse, and the Pidgin judge is weak anyway.
|
| 230 |
+
- **Known weakness:** with `anchor_male`, Flash **under-pauses in Igbo (0.40× native pauses per second) and Yoruba (0.30×)**. Long Igbo or Yoruba passages with the male voice can sound rushed; use a female voice or `--compare` with `phase3` there.
|
| 231 |
+
- Speaker similarity of the anchor drops slightly (0.815 → 0.784), because Flash uses the stock CV3 flow zero-shot instead of the anchor-SFT flow.
|
| 232 |
+
- **UTMOS caveat:** UTMOS22 rates real native speech (3.53) below every synthetic system (3.8–4.3), so it rewards clean studio-like synthesis rather than nativeness. It was not used to choose the model (Phase 3 has the highest UTMOS22: 4.15 anchor / 4.27 female; Flash 3.89 / 4.16; Flash UTMOSv2 3.17 / 3.51). The choice rests on CER, pace and pauses relative to native speech, and clipped endings. Native-speaker MOS / blind A/B is still pending.
|
| 233 |
+
- Text front-end: diacritic restoration word accuracy Yoruba 0.862 (stripped input: 0.171), Igbo 0.968 (0.640).
|
| 234 |
+
|
| 235 |
## Evaluation: Phase 2 vs Phase 3
|
| 236 |
|
| 237 |
183-item eval set (30 per language, 10 code-switched, 3 hand-written + 20 native long-form paragraphs), anchor voice, seed 0. CER is ASR round-trip: MMS-1b-all for Igbo/Hausa/Yoruba, Whisper-large-v3-turbo for English and Pidgin, the lower of the two for code-switched items and paragraphs. "No tones" (in brackets) strips diacritics. SIM is ECAPA cosine to the anchor (ceiling about 0.84 on real held-out anchor clips). The Pidgin judge is weak: real Pidgin recordings score about 0.43.
|
|
|
|
| 275 |
|
| 276 |
## Limitations
|
| 277 |
|
| 278 |
+
- **Flash** (`flash`): the male anchor under-pauses in Igbo and Yoruba (0.40× / 0.30× native pause rate); Pidgin CER is slightly worse than Phase 3; CUDA only; the translate-first mode is experimental and off by default (MADLAD-400 loops on long inputs and is weak on Pidgin); diacritic restoration can still pick the wrong tone on ambiguous words, so write marks yourself where you can. The limitations below for Phase 3 (no laughter, Pidgin data, accent after a switch) apply to Flash too; the pace gap is largely closed for Flash.
|
| 279 |
+
- **Pace (`phase2`/`phase3`)**: speech is still 13–28% slower than native speakers (Igbo 4.60 vs 5.30 syl/s, Hausa 3.77 vs 5.26 syl/s), and there are about half as many pauses per second as in real speech. It can sound careful rather than fully native.
|
| 280 |
- **Pidgin is the weakest language**: only about 5 h of training data, no reliable ASR judge, and the auto-tagger's Pidgin/English split is its weakest point (~0.63 word accuracy on plain Pidgin).
|
| 281 |
- **No laughter or other expressive events**: the training data has effectively no laughter, so tags like `[laughter]` do nothing useful. `[pause]`/`[breath]` were learned from data, but there is no reliable user control over them yet.
|
| 282 |
- English after a Nigerian-language span keeps a strong local accent.
|
|
|
|
| 289 |
|
| 290 |
| path | what it is | licence |
|
| 291 |
|---|---|---|
|
| 292 |
+
| `checkpoints/flash/flash_dpo/` | Flash LM (`best.pt`, sha256 `f59a6fc0…7e3a307`, CosyVoice3 LM + language/speaker/rate embeddings), `config.json`, `spk2id.json`, DPO `args.json`, `log.jsonl` | CC-BY-SA-4.0 |
|
| 293 |
+
| `checkpoints/flash/diacritics_byt5/` | Yoruba/Igbo diacritic-restoration model (fine-tune of [google/byt5-small](https://huggingface.co/google/byt5-small), Apache-2.0) used by the Flash front-end | CC-BY-SA-4.0 |
|
| 294 |
| `checkpoints/phase3/p3_lm_full/` | Phase 3 LM (`best.pt`, val step 4,500), `config.json` (rate, sampler, one-pass, points at the shared Phase 2 flow), `spk2id.json`, `args.json`, `log.jsonl` | CC-BY-SA-4.0 |
|
| 295 |
| `checkpoints/phase2/p2_lm_B/` | Phase 2 LM (`best.pt`) and `spk2id.json` | CC-BY-SA-4.0 |
|
| 296 |
| `checkpoints/phase2/p2_flow_sft/best.pt` | anchor-SFT flow-matching decoder, used by both versions | CC-BY-SA-4.0 |
|
| 297 |
| `prompts/` | anchor prompt clips (`clip0..3`, `prompts.json` with transcripts and S3 tokens) and female voice prompts (`voice_*.wav`, `voices.json`), all from WAXAL | CC-BY-SA-4.0 |
|
| 298 |
+
| `samples/` | example renders (`samples/flash/` for Flash) | CC-BY-SA-4.0 |
|
| 299 |
| `settings.json` | versions, voices, recommended pairing | Apache-2.0 |
|
| 300 |
| `infer.py`, `tagger.py`, `app.py` | inference CLI, auto-tagger, Gradio app | Apache-2.0 |
|
| 301 |
+
| `flash_lm.py`, `frontend/` | Flash model and synthesis code (training code for reference; the data manifest is not shipped), Flash text front-end (normalisation, diacritics, experimental MT) | Apache-2.0 |
|
| 302 |
+
| `prompts/flash_voices_text.json` | transcripts of the voice clips, used as Flash LM prompts | CC-BY-SA-4.0 |
|
| 303 |
| `code/` | the original training and synthesis code, for reference | Apache-2.0 |
|
| 304 |
| `requirements.txt`, `cosyvoice_requirements.txt` | dependencies (`cosyvoice_requirements.txt` is CosyVoice's own file at the commit used) | – |
|
| 305 |
| `assets/` | banner | – |
|
|
|
|
| 314 |
| [Open.Bible Igbo](https://huggingface.co/datasets/AfriSpeech/open-bible-speech-african) (Biblica® Open Igbo Contemporary Bible™, Audio Edition) | Igbo (Phase 3) | CC-BY-SA-4.0 | Biblica, Inc. via open.bible; Biblica® and Open Igbo Contemporary Bible™ are trademarks of Biblica, Inc. |
|
| 315 |
| [NaijaS2ST](https://huggingface.co/datasets/McGill-NLP/NaijaS2ST) (Igbo) | Igbo, many native speakers (Phase 3) | CC-BY-4.0 | McGill-NLP, NaijaS2ST (arXiv:2604.16287) |
|
| 316 |
| [IgboAPI](https://huggingface.co/datasets/nkowaokwu/ibo-dict) (ibo-dict, ibo-dict-expansion) | Igbo sentences (Phase 3) | CC-BY-4.0 | Nkọwa okwu / IgboAPI contributors |
|
| 317 |
+
| [IgboSynCorp](https://doi.org/10.7910/dvn/yb9fwk) | natural Igbo speech (Phase 3); Flash adds pseudo-transcripts of its untranscribed audio | CC0-1.0 | University of Ibadan and Afe Babalola University (Lacuna Fund) |
|
| 318 |
| [FLEURS](https://huggingface.co/datasets/google/fleurs) (English, Hausa, Igbo, Yoruba) | multi-speaker data | CC-BY-4.0 | Google, FLEURS (Conneau et al., 2022) |
|
| 319 |
| [BibleTTS](https://masakhane-io.github.io/bibleTTS/) (Yoruba, Hausa) | Yoruba and Hausa | CC-BY-SA-4.0 | Meyer et al., BibleTTS (2022); Biblica / open.bible audio |
|
| 320 |
| [OpenSLR SLR70](https://openslr.org/70/) (Nigerian English) | English | CC-BY-SA-4.0 | Google, crowdsourced Nigerian English |
|
| 321 |
| [OpenSLR SLR86](https://openslr.org/86/) (Yoruba) | Yoruba | CC-BY-SA-4.0 | Google, crowdsourced Yoruba |
|
| 322 |
| code-switched pairs | about 9 h of synthetic code-switch training pairs | follows the source clips (CC-BY-SA-4.0 / CC-BY-4.0) | built by concatenating clips from the sets above, following the Google 2019 code-switching recipe (Zhang et al., 2019); no separate Google dataset |
|
| 323 |
+
| base model [FunAudioLLM/Fun-CosyVoice3-0.5B-2512](https://huggingface.co/FunAudioLLM/Fun-CosyVoice3-0.5B-2512) | Flash: LM initialisation, flow, vocoder, tokenizers | Apache-2.0 | FunAudioLLM / Alibaba Tongyi Lab, CosyVoice 3 |
|
| 324 |
+
| [google/byt5-small](https://huggingface.co/google/byt5-small) | base of the Flash diacritic-restoration model (fine-tuned on transcripts of the datasets above) | Apache-2.0 | Google, ByT5 (Xue et al., 2022) |
|
| 325 |
| base model [FunAudioLLM/CosyVoice2-0.5B](https://huggingface.co/FunAudioLLM/CosyVoice2-0.5B) | LM initialisation, flow, vocoder, tokenizers | Apache-2.0 | FunAudioLLM / Alibaba Tongyi Lab, CosyVoice 2 (Du et al., 2024) |
|
| 326 |
| optional [GlotLID](https://huggingface.co/cis-lmu/glotlid) (not bundled) | `--lid glotlid` in the tagger | Apache-2.0 plus notices | Kargaran et al., GlotLID (EMNLP 2023) |
|
| 327 |
|
| 328 |
+
Flash's training data is the licensed set above (the same sources as Phase 3, re-weighted with less Bible narration and slow read speech, plus IgboSynCorp pseudo-transcripts); its DPO pairs are the model's own renders of eval-style prompts, scored automatically. Excluded on licence grounds from every released checkpoint, Flash included: African Voices / WaZoBiaSpeech (its cards ban TTS use), NaijaVoices (non-commercial), and non-commercial TTS weights. The optional MADLAD-400-3B-MT translator (Apache-2.0) is not bundled; NLLB was avoided because it is non-commercial.
|
| 329 |
|
| 330 |
## Licence
|
| 331 |
|
| 332 |
- **Model weights, voice prompts and samples** (`checkpoints/`, `prompts/`, `samples/`): **[CC-BY-SA-4.0](LICENSE)**. You may use them commercially. You must credit Modular and the datasets listed above, and anything you derive from the weights (fine-tunes, merges) must be shared under CC-BY-SA-4.0 too.
|
| 333 |
+
- **Code** (`infer.py`, `tagger.py`, `app.py`, `flash_lm.py`, `frontend/`, `code/`, `settings.json`): **[Apache-2.0](LICENSE-CODE)**.
|
| 334 |
+
- The base models, CosyVoice2-0.5B and Fun-CosyVoice3-0.5B-2512 (and byt5-small for the diacritic model), are Apache-2.0; their notices still apply to the parts they contribute.
|
| 335 |
|
| 336 |
## Citation
|
| 337 |
|
app.py
CHANGED
|
@@ -5,8 +5,8 @@
|
|
| 5 |
python app.py --cosyvoice_dir ../CosyVoice # then open http://127.0.0.1:7860
|
| 6 |
|
| 7 |
Text box -> optional auto-tag (editable preview of the tagged text) -> version + voice + rate -> Synthesize, or
|
| 8 |
-
Compare to hear Phase
|
| 9 |
-
base;
|
| 10 |
"""
|
| 11 |
import argparse, json, os, sys, types
|
| 12 |
|
|
@@ -35,7 +35,8 @@ class Engine:
|
|
| 35 |
ns = types.SimpleNamespace(**vars(self.a))
|
| 36 |
ns.voice = voice
|
| 37 |
S = infer.build(version, ns, self.cosy, self.tok, copy_llm=self.cosy is not None)
|
| 38 |
-
|
|
|
|
| 39 |
S._rate0 = S.rate
|
| 40 |
self.models[version] = S
|
| 41 |
S = self.models[version]
|
|
@@ -65,7 +66,9 @@ def main():
|
|
| 65 |
ap.add_argument("--share", action="store_true")
|
| 66 |
a = ap.parse_args()
|
| 67 |
for k, v in dict(lm="", flow="", prompts=os.path.join(HERE, "prompts", "prompts.json"),
|
| 68 |
-
voices=os.path.join(HERE, "prompts", "voices.json"), dtype="auto", stitch=False, rate="default"
|
|
|
|
|
|
|
| 69 |
setattr(a, k, v)
|
| 70 |
if not os.path.isdir(a.model_dir):
|
| 71 |
from huggingface_hub import snapshot_download
|
|
@@ -98,9 +101,9 @@ def main():
|
|
| 98 |
|
| 99 |
def compare(text, tagged, auto, lang_map, use_lid, force, voice, rate, seed):
|
| 100 |
t = tagged.strip() if tagged.strip() else prepare(text, auto, lang_map, use_lid, force)
|
| 101 |
-
a2 = E.say(t, "phase2", voice, rate, seed)
|
| 102 |
a3 = E.say(t, "phase3", voice, rate, seed)
|
| 103 |
-
|
|
|
|
| 104 |
|
| 105 |
with gr.Blocks(title="Dynamic Accent: code-switching TTS") as demo:
|
| 106 |
gr.Markdown("## Dynamic Accent: code-switching TTS\nEnglish, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed in one "
|
|
@@ -114,18 +117,18 @@ def main():
|
|
| 114 |
tag_btn = gr.Button("Preview tags")
|
| 115 |
tagged = gr.Textbox(label="Tagged text (edit before synthesis; leave empty to tag automatically)", lines=3)
|
| 116 |
with gr.Row():
|
| 117 |
-
version = gr.Dropdown(sorted(infer.VERSIONS), value=S.get("default_version", "
|
| 118 |
voice = gr.Dropdown(voices, value=S.get("default_voice", "anchor_male"), label="Voice")
|
| 119 |
-
rate = gr.Dropdown(rates, value="default", label="Rate (phase3)")
|
| 120 |
seed = gr.Number(value=0, precision=0, label="Seed")
|
| 121 |
tip = gr.Markdown()
|
| 122 |
with gr.Row():
|
| 123 |
go = gr.Button("Synthesize", variant="primary")
|
| 124 |
-
cmp_btn = gr.Button("Compare Phase
|
| 125 |
out = gr.Audio(label="Output", type="numpy")
|
| 126 |
with gr.Row():
|
| 127 |
-
out2 = gr.Audio(label="Phase
|
| 128 |
-
out3 = gr.Audio(label="
|
| 129 |
gr.Examples(EXAMPLES, inputs=text)
|
| 130 |
|
| 131 |
tag_btn.click(prepare, [text, auto, lang_map, use_lid, force], tagged)
|
|
|
|
| 5 |
python app.py --cosyvoice_dir ../CosyVoice # then open http://127.0.0.1:7860
|
| 6 |
|
| 7 |
Text box -> optional auto-tag (editable preview of the tagged text) -> version + voice + rate -> Synthesize, or
|
| 8 |
+
Compare to hear Phase 3 and Flash on the same text, seed and voice. Loaded versions stay resident (Phase 2/3 share one
|
| 9 |
+
CosyVoice2 base; Flash has its own CosyVoice3 base), so a GPU with >= 24 GB is recommended. Flash needs CUDA.
|
| 10 |
"""
|
| 11 |
import argparse, json, os, sys, types
|
| 12 |
|
|
|
|
| 35 |
ns = types.SimpleNamespace(**vars(self.a))
|
| 36 |
ns.voice = voice
|
| 37 |
S = infer.build(version, ns, self.cosy, self.tok, copy_llm=self.cosy is not None)
|
| 38 |
+
if S.cosy is not None: # flash (CosyVoice3) keeps its own base
|
| 39 |
+
self.cosy, self.tok = S.cosy, S.tok
|
| 40 |
S._rate0 = S.rate
|
| 41 |
self.models[version] = S
|
| 42 |
S = self.models[version]
|
|
|
|
| 66 |
ap.add_argument("--share", action="store_true")
|
| 67 |
a = ap.parse_args()
|
| 68 |
for k, v in dict(lm="", flow="", prompts=os.path.join(HERE, "prompts", "prompts.json"),
|
| 69 |
+
voices=os.path.join(HERE, "prompts", "voices.json"), dtype="auto", stitch=False, rate="default",
|
| 70 |
+
frontend="codeswitch", frontend_lang="eng", no_diacritics=False, experimental_translate=False,
|
| 71 |
+
cv3_dir=os.environ.get("CV3_DIR", os.path.join(HERE, "pretrained", "Fun-CosyVoice3-0.5B-2512"))).items():
|
| 72 |
setattr(a, k, v)
|
| 73 |
if not os.path.isdir(a.model_dir):
|
| 74 |
from huggingface_hub import snapshot_download
|
|
|
|
| 101 |
|
| 102 |
def compare(text, tagged, auto, lang_map, use_lid, force, voice, rate, seed):
|
| 103 |
t = tagged.strip() if tagged.strip() else prepare(text, auto, lang_map, use_lid, force)
|
|
|
|
| 104 |
a3 = E.say(t, "phase3", voice, rate, seed)
|
| 105 |
+
af = E.say(t, "flash", voice, rate, seed)
|
| 106 |
+
return t, a3, af
|
| 107 |
|
| 108 |
with gr.Blocks(title="Dynamic Accent: code-switching TTS") as demo:
|
| 109 |
gr.Markdown("## Dynamic Accent: code-switching TTS\nEnglish, Nigerian Pidgin, Igbo, Yoruba and Hausa, mixed in one "
|
|
|
|
| 117 |
tag_btn = gr.Button("Preview tags")
|
| 118 |
tagged = gr.Textbox(label="Tagged text (edit before synthesis; leave empty to tag automatically)", lines=3)
|
| 119 |
with gr.Row():
|
| 120 |
+
version = gr.Dropdown(sorted(infer.VERSIONS), value=S.get("default_version", "flash"), label="Version")
|
| 121 |
voice = gr.Dropdown(voices, value=S.get("default_voice", "anchor_male"), label="Voice")
|
| 122 |
+
rate = gr.Dropdown(rates, value="default", label="Rate (phase3/flash)")
|
| 123 |
seed = gr.Number(value=0, precision=0, label="Seed")
|
| 124 |
tip = gr.Markdown()
|
| 125 |
with gr.Row():
|
| 126 |
go = gr.Button("Synthesize", variant="primary")
|
| 127 |
+
cmp_btn = gr.Button("Compare Phase 3 vs Flash")
|
| 128 |
out = gr.Audio(label="Output", type="numpy")
|
| 129 |
with gr.Row():
|
| 130 |
+
out2 = gr.Audio(label="Phase 3", type="numpy")
|
| 131 |
+
out3 = gr.Audio(label="Flash", type="numpy")
|
| 132 |
gr.Examples(EXAMPLES, inputs=text)
|
| 133 |
|
| 134 |
tag_btn.click(prepare, [text, auto, lang_map, use_lid, force], tagged)
|
checkpoints/flash/diacritics_byt5/added_tokens.json
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"<extra_id_0>": 259,
|
| 3 |
+
"<extra_id_100>": 359,
|
| 4 |
+
"<extra_id_101>": 360,
|
| 5 |
+
"<extra_id_102>": 361,
|
| 6 |
+
"<extra_id_103>": 362,
|
| 7 |
+
"<extra_id_104>": 363,
|
| 8 |
+
"<extra_id_105>": 364,
|
| 9 |
+
"<extra_id_106>": 365,
|
| 10 |
+
"<extra_id_107>": 366,
|
| 11 |
+
"<extra_id_108>": 367,
|
| 12 |
+
"<extra_id_109>": 368,
|
| 13 |
+
"<extra_id_10>": 269,
|
| 14 |
+
"<extra_id_110>": 369,
|
| 15 |
+
"<extra_id_111>": 370,
|
| 16 |
+
"<extra_id_112>": 371,
|
| 17 |
+
"<extra_id_113>": 372,
|
| 18 |
+
"<extra_id_114>": 373,
|
| 19 |
+
"<extra_id_115>": 374,
|
| 20 |
+
"<extra_id_116>": 375,
|
| 21 |
+
"<extra_id_117>": 376,
|
| 22 |
+
"<extra_id_118>": 377,
|
| 23 |
+
"<extra_id_119>": 378,
|
| 24 |
+
"<extra_id_11>": 270,
|
| 25 |
+
"<extra_id_120>": 379,
|
| 26 |
+
"<extra_id_121>": 380,
|
| 27 |
+
"<extra_id_122>": 381,
|
| 28 |
+
"<extra_id_123>": 382,
|
| 29 |
+
"<extra_id_124>": 383,
|
| 30 |
+
"<extra_id_12>": 271,
|
| 31 |
+
"<extra_id_13>": 272,
|
| 32 |
+
"<extra_id_14>": 273,
|
| 33 |
+
"<extra_id_15>": 274,
|
| 34 |
+
"<extra_id_16>": 275,
|
| 35 |
+
"<extra_id_17>": 276,
|
| 36 |
+
"<extra_id_18>": 277,
|
| 37 |
+
"<extra_id_19>": 278,
|
| 38 |
+
"<extra_id_1>": 260,
|
| 39 |
+
"<extra_id_20>": 279,
|
| 40 |
+
"<extra_id_21>": 280,
|
| 41 |
+
"<extra_id_22>": 281,
|
| 42 |
+
"<extra_id_23>": 282,
|
| 43 |
+
"<extra_id_24>": 283,
|
| 44 |
+
"<extra_id_25>": 284,
|
| 45 |
+
"<extra_id_26>": 285,
|
| 46 |
+
"<extra_id_27>": 286,
|
| 47 |
+
"<extra_id_28>": 287,
|
| 48 |
+
"<extra_id_29>": 288,
|
| 49 |
+
"<extra_id_2>": 261,
|
| 50 |
+
"<extra_id_30>": 289,
|
| 51 |
+
"<extra_id_31>": 290,
|
| 52 |
+
"<extra_id_32>": 291,
|
| 53 |
+
"<extra_id_33>": 292,
|
| 54 |
+
"<extra_id_34>": 293,
|
| 55 |
+
"<extra_id_35>": 294,
|
| 56 |
+
"<extra_id_36>": 295,
|
| 57 |
+
"<extra_id_37>": 296,
|
| 58 |
+
"<extra_id_38>": 297,
|
| 59 |
+
"<extra_id_39>": 298,
|
| 60 |
+
"<extra_id_3>": 262,
|
| 61 |
+
"<extra_id_40>": 299,
|
| 62 |
+
"<extra_id_41>": 300,
|
| 63 |
+
"<extra_id_42>": 301,
|
| 64 |
+
"<extra_id_43>": 302,
|
| 65 |
+
"<extra_id_44>": 303,
|
| 66 |
+
"<extra_id_45>": 304,
|
| 67 |
+
"<extra_id_46>": 305,
|
| 68 |
+
"<extra_id_47>": 306,
|
| 69 |
+
"<extra_id_48>": 307,
|
| 70 |
+
"<extra_id_49>": 308,
|
| 71 |
+
"<extra_id_4>": 263,
|
| 72 |
+
"<extra_id_50>": 309,
|
| 73 |
+
"<extra_id_51>": 310,
|
| 74 |
+
"<extra_id_52>": 311,
|
| 75 |
+
"<extra_id_53>": 312,
|
| 76 |
+
"<extra_id_54>": 313,
|
| 77 |
+
"<extra_id_55>": 314,
|
| 78 |
+
"<extra_id_56>": 315,
|
| 79 |
+
"<extra_id_57>": 316,
|
| 80 |
+
"<extra_id_58>": 317,
|
| 81 |
+
"<extra_id_59>": 318,
|
| 82 |
+
"<extra_id_5>": 264,
|
| 83 |
+
"<extra_id_60>": 319,
|
| 84 |
+
"<extra_id_61>": 320,
|
| 85 |
+
"<extra_id_62>": 321,
|
| 86 |
+
"<extra_id_63>": 322,
|
| 87 |
+
"<extra_id_64>": 323,
|
| 88 |
+
"<extra_id_65>": 324,
|
| 89 |
+
"<extra_id_66>": 325,
|
| 90 |
+
"<extra_id_67>": 326,
|
| 91 |
+
"<extra_id_68>": 327,
|
| 92 |
+
"<extra_id_69>": 328,
|
| 93 |
+
"<extra_id_6>": 265,
|
| 94 |
+
"<extra_id_70>": 329,
|
| 95 |
+
"<extra_id_71>": 330,
|
| 96 |
+
"<extra_id_72>": 331,
|
| 97 |
+
"<extra_id_73>": 332,
|
| 98 |
+
"<extra_id_74>": 333,
|
| 99 |
+
"<extra_id_75>": 334,
|
| 100 |
+
"<extra_id_76>": 335,
|
| 101 |
+
"<extra_id_77>": 336,
|
| 102 |
+
"<extra_id_78>": 337,
|
| 103 |
+
"<extra_id_79>": 338,
|
| 104 |
+
"<extra_id_7>": 266,
|
| 105 |
+
"<extra_id_80>": 339,
|
| 106 |
+
"<extra_id_81>": 340,
|
| 107 |
+
"<extra_id_82>": 341,
|
| 108 |
+
"<extra_id_83>": 342,
|
| 109 |
+
"<extra_id_84>": 343,
|
| 110 |
+
"<extra_id_85>": 344,
|
| 111 |
+
"<extra_id_86>": 345,
|
| 112 |
+
"<extra_id_87>": 346,
|
| 113 |
+
"<extra_id_88>": 347,
|
| 114 |
+
"<extra_id_89>": 348,
|
| 115 |
+
"<extra_id_8>": 267,
|
| 116 |
+
"<extra_id_90>": 349,
|
| 117 |
+
"<extra_id_91>": 350,
|
| 118 |
+
"<extra_id_92>": 351,
|
| 119 |
+
"<extra_id_93>": 352,
|
| 120 |
+
"<extra_id_94>": 353,
|
| 121 |
+
"<extra_id_95>": 354,
|
| 122 |
+
"<extra_id_96>": 355,
|
| 123 |
+
"<extra_id_97>": 356,
|
| 124 |
+
"<extra_id_98>": 357,
|
| 125 |
+
"<extra_id_99>": 358,
|
| 126 |
+
"<extra_id_9>": 268
|
| 127 |
+
}
|
checkpoints/flash/diacritics_byt5/config.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"architectures": [
|
| 3 |
+
"T5ForConditionalGeneration"
|
| 4 |
+
],
|
| 5 |
+
"classifier_dropout": 0.0,
|
| 6 |
+
"d_ff": 3584,
|
| 7 |
+
"d_kv": 64,
|
| 8 |
+
"d_model": 1472,
|
| 9 |
+
"decoder_start_token_id": 0,
|
| 10 |
+
"dense_act_fn": "gelu_new",
|
| 11 |
+
"dropout_rate": 0.1,
|
| 12 |
+
"eos_token_id": 1,
|
| 13 |
+
"feed_forward_proj": "gated-gelu",
|
| 14 |
+
"gradient_checkpointing": false,
|
| 15 |
+
"initializer_factor": 1.0,
|
| 16 |
+
"is_encoder_decoder": true,
|
| 17 |
+
"is_gated_act": true,
|
| 18 |
+
"layer_norm_epsilon": 1e-06,
|
| 19 |
+
"model_type": "t5",
|
| 20 |
+
"num_decoder_layers": 4,
|
| 21 |
+
"num_heads": 6,
|
| 22 |
+
"num_layers": 12,
|
| 23 |
+
"pad_token_id": 0,
|
| 24 |
+
"relative_attention_max_distance": 128,
|
| 25 |
+
"relative_attention_num_buckets": 32,
|
| 26 |
+
"tie_word_embeddings": false,
|
| 27 |
+
"tokenizer_class": "ByT5Tokenizer",
|
| 28 |
+
"torch_dtype": "float32",
|
| 29 |
+
"transformers_version": "4.51.3",
|
| 30 |
+
"use_cache": true,
|
| 31 |
+
"vocab_size": 384
|
| 32 |
+
}
|
checkpoints/flash/diacritics_byt5/generation_config.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"_from_model_config": true,
|
| 3 |
+
"decoder_start_token_id": 0,
|
| 4 |
+
"eos_token_id": 1,
|
| 5 |
+
"pad_token_id": 0,
|
| 6 |
+
"transformers_version": "4.51.3"
|
| 7 |
+
}
|
checkpoints/flash/diacritics_byt5/model.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:27c2f5f06306a51af9f6107c38aebff2606d7589cd4f870a4478c7b7047f789e
|
| 3 |
+
size 1198571496
|
checkpoints/flash/diacritics_byt5/special_tokens_map.json
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"additional_special_tokens": [
|
| 3 |
+
"<extra_id_0>",
|
| 4 |
+
"<extra_id_1>",
|
| 5 |
+
"<extra_id_2>",
|
| 6 |
+
"<extra_id_3>",
|
| 7 |
+
"<extra_id_4>",
|
| 8 |
+
"<extra_id_5>",
|
| 9 |
+
"<extra_id_6>",
|
| 10 |
+
"<extra_id_7>",
|
| 11 |
+
"<extra_id_8>",
|
| 12 |
+
"<extra_id_9>",
|
| 13 |
+
"<extra_id_10>",
|
| 14 |
+
"<extra_id_11>",
|
| 15 |
+
"<extra_id_12>",
|
| 16 |
+
"<extra_id_13>",
|
| 17 |
+
"<extra_id_14>",
|
| 18 |
+
"<extra_id_15>",
|
| 19 |
+
"<extra_id_16>",
|
| 20 |
+
"<extra_id_17>",
|
| 21 |
+
"<extra_id_18>",
|
| 22 |
+
"<extra_id_19>",
|
| 23 |
+
"<extra_id_20>",
|
| 24 |
+
"<extra_id_21>",
|
| 25 |
+
"<extra_id_22>",
|
| 26 |
+
"<extra_id_23>",
|
| 27 |
+
"<extra_id_24>",
|
| 28 |
+
"<extra_id_25>",
|
| 29 |
+
"<extra_id_26>",
|
| 30 |
+
"<extra_id_27>",
|
| 31 |
+
"<extra_id_28>",
|
| 32 |
+
"<extra_id_29>",
|
| 33 |
+
"<extra_id_30>",
|
| 34 |
+
"<extra_id_31>",
|
| 35 |
+
"<extra_id_32>",
|
| 36 |
+
"<extra_id_33>",
|
| 37 |
+
"<extra_id_34>",
|
| 38 |
+
"<extra_id_35>",
|
| 39 |
+
"<extra_id_36>",
|
| 40 |
+
"<extra_id_37>",
|
| 41 |
+
"<extra_id_38>",
|
| 42 |
+
"<extra_id_39>",
|
| 43 |
+
"<extra_id_40>",
|
| 44 |
+
"<extra_id_41>",
|
| 45 |
+
"<extra_id_42>",
|
| 46 |
+
"<extra_id_43>",
|
| 47 |
+
"<extra_id_44>",
|
| 48 |
+
"<extra_id_45>",
|
| 49 |
+
"<extra_id_46>",
|
| 50 |
+
"<extra_id_47>",
|
| 51 |
+
"<extra_id_48>",
|
| 52 |
+
"<extra_id_49>",
|
| 53 |
+
"<extra_id_50>",
|
| 54 |
+
"<extra_id_51>",
|
| 55 |
+
"<extra_id_52>",
|
| 56 |
+
"<extra_id_53>",
|
| 57 |
+
"<extra_id_54>",
|
| 58 |
+
"<extra_id_55>",
|
| 59 |
+
"<extra_id_56>",
|
| 60 |
+
"<extra_id_57>",
|
| 61 |
+
"<extra_id_58>",
|
| 62 |
+
"<extra_id_59>",
|
| 63 |
+
"<extra_id_60>",
|
| 64 |
+
"<extra_id_61>",
|
| 65 |
+
"<extra_id_62>",
|
| 66 |
+
"<extra_id_63>",
|
| 67 |
+
"<extra_id_64>",
|
| 68 |
+
"<extra_id_65>",
|
| 69 |
+
"<extra_id_66>",
|
| 70 |
+
"<extra_id_67>",
|
| 71 |
+
"<extra_id_68>",
|
| 72 |
+
"<extra_id_69>",
|
| 73 |
+
"<extra_id_70>",
|
| 74 |
+
"<extra_id_71>",
|
| 75 |
+
"<extra_id_72>",
|
| 76 |
+
"<extra_id_73>",
|
| 77 |
+
"<extra_id_74>",
|
| 78 |
+
"<extra_id_75>",
|
| 79 |
+
"<extra_id_76>",
|
| 80 |
+
"<extra_id_77>",
|
| 81 |
+
"<extra_id_78>",
|
| 82 |
+
"<extra_id_79>",
|
| 83 |
+
"<extra_id_80>",
|
| 84 |
+
"<extra_id_81>",
|
| 85 |
+
"<extra_id_82>",
|
| 86 |
+
"<extra_id_83>",
|
| 87 |
+
"<extra_id_84>",
|
| 88 |
+
"<extra_id_85>",
|
| 89 |
+
"<extra_id_86>",
|
| 90 |
+
"<extra_id_87>",
|
| 91 |
+
"<extra_id_88>",
|
| 92 |
+
"<extra_id_89>",
|
| 93 |
+
"<extra_id_90>",
|
| 94 |
+
"<extra_id_91>",
|
| 95 |
+
"<extra_id_92>",
|
| 96 |
+
"<extra_id_93>",
|
| 97 |
+
"<extra_id_94>",
|
| 98 |
+
"<extra_id_95>",
|
| 99 |
+
"<extra_id_96>",
|
| 100 |
+
"<extra_id_97>",
|
| 101 |
+
"<extra_id_98>",
|
| 102 |
+
"<extra_id_99>",
|
| 103 |
+
"<extra_id_100>",
|
| 104 |
+
"<extra_id_101>",
|
| 105 |
+
"<extra_id_102>",
|
| 106 |
+
"<extra_id_103>",
|
| 107 |
+
"<extra_id_104>",
|
| 108 |
+
"<extra_id_105>",
|
| 109 |
+
"<extra_id_106>",
|
| 110 |
+
"<extra_id_107>",
|
| 111 |
+
"<extra_id_108>",
|
| 112 |
+
"<extra_id_109>",
|
| 113 |
+
"<extra_id_110>",
|
| 114 |
+
"<extra_id_111>",
|
| 115 |
+
"<extra_id_112>",
|
| 116 |
+
"<extra_id_113>",
|
| 117 |
+
"<extra_id_114>",
|
| 118 |
+
"<extra_id_115>",
|
| 119 |
+
"<extra_id_116>",
|
| 120 |
+
"<extra_id_117>",
|
| 121 |
+
"<extra_id_118>",
|
| 122 |
+
"<extra_id_119>",
|
| 123 |
+
"<extra_id_120>",
|
| 124 |
+
"<extra_id_121>",
|
| 125 |
+
"<extra_id_122>",
|
| 126 |
+
"<extra_id_123>",
|
| 127 |
+
"<extra_id_124>"
|
| 128 |
+
],
|
| 129 |
+
"eos_token": {
|
| 130 |
+
"content": "</s>",
|
| 131 |
+
"lstrip": false,
|
| 132 |
+
"normalized": true,
|
| 133 |
+
"rstrip": false,
|
| 134 |
+
"single_word": false
|
| 135 |
+
},
|
| 136 |
+
"pad_token": {
|
| 137 |
+
"content": "<pad>",
|
| 138 |
+
"lstrip": false,
|
| 139 |
+
"normalized": true,
|
| 140 |
+
"rstrip": false,
|
| 141 |
+
"single_word": false
|
| 142 |
+
},
|
| 143 |
+
"unk_token": {
|
| 144 |
+
"content": "<unk>",
|
| 145 |
+
"lstrip": false,
|
| 146 |
+
"normalized": true,
|
| 147 |
+
"rstrip": false,
|
| 148 |
+
"single_word": false
|
| 149 |
+
}
|
| 150 |
+
}
|
checkpoints/flash/diacritics_byt5/tokenizer_config.json
ADDED
|
@@ -0,0 +1,1163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"added_tokens_decoder": {
|
| 3 |
+
"0": {
|
| 4 |
+
"content": "<pad>",
|
| 5 |
+
"lstrip": false,
|
| 6 |
+
"normalized": true,
|
| 7 |
+
"rstrip": false,
|
| 8 |
+
"single_word": false,
|
| 9 |
+
"special": true
|
| 10 |
+
},
|
| 11 |
+
"1": {
|
| 12 |
+
"content": "</s>",
|
| 13 |
+
"lstrip": false,
|
| 14 |
+
"normalized": true,
|
| 15 |
+
"rstrip": false,
|
| 16 |
+
"single_word": false,
|
| 17 |
+
"special": true
|
| 18 |
+
},
|
| 19 |
+
"2": {
|
| 20 |
+
"content": "<unk>",
|
| 21 |
+
"lstrip": false,
|
| 22 |
+
"normalized": true,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false,
|
| 25 |
+
"special": true
|
| 26 |
+
},
|
| 27 |
+
"259": {
|
| 28 |
+
"content": "<extra_id_0>",
|
| 29 |
+
"lstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false,
|
| 33 |
+
"special": true
|
| 34 |
+
},
|
| 35 |
+
"260": {
|
| 36 |
+
"content": "<extra_id_1>",
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"normalized": false,
|
| 39 |
+
"rstrip": false,
|
| 40 |
+
"single_word": false,
|
| 41 |
+
"special": true
|
| 42 |
+
},
|
| 43 |
+
"261": {
|
| 44 |
+
"content": "<extra_id_2>",
|
| 45 |
+
"lstrip": false,
|
| 46 |
+
"normalized": false,
|
| 47 |
+
"rstrip": false,
|
| 48 |
+
"single_word": false,
|
| 49 |
+
"special": true
|
| 50 |
+
},
|
| 51 |
+
"262": {
|
| 52 |
+
"content": "<extra_id_3>",
|
| 53 |
+
"lstrip": false,
|
| 54 |
+
"normalized": false,
|
| 55 |
+
"rstrip": false,
|
| 56 |
+
"single_word": false,
|
| 57 |
+
"special": true
|
| 58 |
+
},
|
| 59 |
+
"263": {
|
| 60 |
+
"content": "<extra_id_4>",
|
| 61 |
+
"lstrip": false,
|
| 62 |
+
"normalized": false,
|
| 63 |
+
"rstrip": false,
|
| 64 |
+
"single_word": false,
|
| 65 |
+
"special": true
|
| 66 |
+
},
|
| 67 |
+
"264": {
|
| 68 |
+
"content": "<extra_id_5>",
|
| 69 |
+
"lstrip": false,
|
| 70 |
+
"normalized": false,
|
| 71 |
+
"rstrip": false,
|
| 72 |
+
"single_word": false,
|
| 73 |
+
"special": true
|
| 74 |
+
},
|
| 75 |
+
"265": {
|
| 76 |
+
"content": "<extra_id_6>",
|
| 77 |
+
"lstrip": false,
|
| 78 |
+
"normalized": false,
|
| 79 |
+
"rstrip": false,
|
| 80 |
+
"single_word": false,
|
| 81 |
+
"special": true
|
| 82 |
+
},
|
| 83 |
+
"266": {
|
| 84 |
+
"content": "<extra_id_7>",
|
| 85 |
+
"lstrip": false,
|
| 86 |
+
"normalized": false,
|
| 87 |
+
"rstrip": false,
|
| 88 |
+
"single_word": false,
|
| 89 |
+
"special": true
|
| 90 |
+
},
|
| 91 |
+
"267": {
|
| 92 |
+
"content": "<extra_id_8>",
|
| 93 |
+
"lstrip": false,
|
| 94 |
+
"normalized": false,
|
| 95 |
+
"rstrip": false,
|
| 96 |
+
"single_word": false,
|
| 97 |
+
"special": true
|
| 98 |
+
},
|
| 99 |
+
"268": {
|
| 100 |
+
"content": "<extra_id_9>",
|
| 101 |
+
"lstrip": false,
|
| 102 |
+
"normalized": false,
|
| 103 |
+
"rstrip": false,
|
| 104 |
+
"single_word": false,
|
| 105 |
+
"special": true
|
| 106 |
+
},
|
| 107 |
+
"269": {
|
| 108 |
+
"content": "<extra_id_10>",
|
| 109 |
+
"lstrip": false,
|
| 110 |
+
"normalized": false,
|
| 111 |
+
"rstrip": false,
|
| 112 |
+
"single_word": false,
|
| 113 |
+
"special": true
|
| 114 |
+
},
|
| 115 |
+
"270": {
|
| 116 |
+
"content": "<extra_id_11>",
|
| 117 |
+
"lstrip": false,
|
| 118 |
+
"normalized": false,
|
| 119 |
+
"rstrip": false,
|
| 120 |
+
"single_word": false,
|
| 121 |
+
"special": true
|
| 122 |
+
},
|
| 123 |
+
"271": {
|
| 124 |
+
"content": "<extra_id_12>",
|
| 125 |
+
"lstrip": false,
|
| 126 |
+
"normalized": false,
|
| 127 |
+
"rstrip": false,
|
| 128 |
+
"single_word": false,
|
| 129 |
+
"special": true
|
| 130 |
+
},
|
| 131 |
+
"272": {
|
| 132 |
+
"content": "<extra_id_13>",
|
| 133 |
+
"lstrip": false,
|
| 134 |
+
"normalized": false,
|
| 135 |
+
"rstrip": false,
|
| 136 |
+
"single_word": false,
|
| 137 |
+
"special": true
|
| 138 |
+
},
|
| 139 |
+
"273": {
|
| 140 |
+
"content": "<extra_id_14>",
|
| 141 |
+
"lstrip": false,
|
| 142 |
+
"normalized": false,
|
| 143 |
+
"rstrip": false,
|
| 144 |
+
"single_word": false,
|
| 145 |
+
"special": true
|
| 146 |
+
},
|
| 147 |
+
"274": {
|
| 148 |
+
"content": "<extra_id_15>",
|
| 149 |
+
"lstrip": false,
|
| 150 |
+
"normalized": false,
|
| 151 |
+
"rstrip": false,
|
| 152 |
+
"single_word": false,
|
| 153 |
+
"special": true
|
| 154 |
+
},
|
| 155 |
+
"275": {
|
| 156 |
+
"content": "<extra_id_16>",
|
| 157 |
+
"lstrip": false,
|
| 158 |
+
"normalized": false,
|
| 159 |
+
"rstrip": false,
|
| 160 |
+
"single_word": false,
|
| 161 |
+
"special": true
|
| 162 |
+
},
|
| 163 |
+
"276": {
|
| 164 |
+
"content": "<extra_id_17>",
|
| 165 |
+
"lstrip": false,
|
| 166 |
+
"normalized": false,
|
| 167 |
+
"rstrip": false,
|
| 168 |
+
"single_word": false,
|
| 169 |
+
"special": true
|
| 170 |
+
},
|
| 171 |
+
"277": {
|
| 172 |
+
"content": "<extra_id_18>",
|
| 173 |
+
"lstrip": false,
|
| 174 |
+
"normalized": false,
|
| 175 |
+
"rstrip": false,
|
| 176 |
+
"single_word": false,
|
| 177 |
+
"special": true
|
| 178 |
+
},
|
| 179 |
+
"278": {
|
| 180 |
+
"content": "<extra_id_19>",
|
| 181 |
+
"lstrip": false,
|
| 182 |
+
"normalized": false,
|
| 183 |
+
"rstrip": false,
|
| 184 |
+
"single_word": false,
|
| 185 |
+
"special": true
|
| 186 |
+
},
|
| 187 |
+
"279": {
|
| 188 |
+
"content": "<extra_id_20>",
|
| 189 |
+
"lstrip": false,
|
| 190 |
+
"normalized": false,
|
| 191 |
+
"rstrip": false,
|
| 192 |
+
"single_word": false,
|
| 193 |
+
"special": true
|
| 194 |
+
},
|
| 195 |
+
"280": {
|
| 196 |
+
"content": "<extra_id_21>",
|
| 197 |
+
"lstrip": false,
|
| 198 |
+
"normalized": false,
|
| 199 |
+
"rstrip": false,
|
| 200 |
+
"single_word": false,
|
| 201 |
+
"special": true
|
| 202 |
+
},
|
| 203 |
+
"281": {
|
| 204 |
+
"content": "<extra_id_22>",
|
| 205 |
+
"lstrip": false,
|
| 206 |
+
"normalized": false,
|
| 207 |
+
"rstrip": false,
|
| 208 |
+
"single_word": false,
|
| 209 |
+
"special": true
|
| 210 |
+
},
|
| 211 |
+
"282": {
|
| 212 |
+
"content": "<extra_id_23>",
|
| 213 |
+
"lstrip": false,
|
| 214 |
+
"normalized": false,
|
| 215 |
+
"rstrip": false,
|
| 216 |
+
"single_word": false,
|
| 217 |
+
"special": true
|
| 218 |
+
},
|
| 219 |
+
"283": {
|
| 220 |
+
"content": "<extra_id_24>",
|
| 221 |
+
"lstrip": false,
|
| 222 |
+
"normalized": false,
|
| 223 |
+
"rstrip": false,
|
| 224 |
+
"single_word": false,
|
| 225 |
+
"special": true
|
| 226 |
+
},
|
| 227 |
+
"284": {
|
| 228 |
+
"content": "<extra_id_25>",
|
| 229 |
+
"lstrip": false,
|
| 230 |
+
"normalized": false,
|
| 231 |
+
"rstrip": false,
|
| 232 |
+
"single_word": false,
|
| 233 |
+
"special": true
|
| 234 |
+
},
|
| 235 |
+
"285": {
|
| 236 |
+
"content": "<extra_id_26>",
|
| 237 |
+
"lstrip": false,
|
| 238 |
+
"normalized": false,
|
| 239 |
+
"rstrip": false,
|
| 240 |
+
"single_word": false,
|
| 241 |
+
"special": true
|
| 242 |
+
},
|
| 243 |
+
"286": {
|
| 244 |
+
"content": "<extra_id_27>",
|
| 245 |
+
"lstrip": false,
|
| 246 |
+
"normalized": false,
|
| 247 |
+
"rstrip": false,
|
| 248 |
+
"single_word": false,
|
| 249 |
+
"special": true
|
| 250 |
+
},
|
| 251 |
+
"287": {
|
| 252 |
+
"content": "<extra_id_28>",
|
| 253 |
+
"lstrip": false,
|
| 254 |
+
"normalized": false,
|
| 255 |
+
"rstrip": false,
|
| 256 |
+
"single_word": false,
|
| 257 |
+
"special": true
|
| 258 |
+
},
|
| 259 |
+
"288": {
|
| 260 |
+
"content": "<extra_id_29>",
|
| 261 |
+
"lstrip": false,
|
| 262 |
+
"normalized": false,
|
| 263 |
+
"rstrip": false,
|
| 264 |
+
"single_word": false,
|
| 265 |
+
"special": true
|
| 266 |
+
},
|
| 267 |
+
"289": {
|
| 268 |
+
"content": "<extra_id_30>",
|
| 269 |
+
"lstrip": false,
|
| 270 |
+
"normalized": false,
|
| 271 |
+
"rstrip": false,
|
| 272 |
+
"single_word": false,
|
| 273 |
+
"special": true
|
| 274 |
+
},
|
| 275 |
+
"290": {
|
| 276 |
+
"content": "<extra_id_31>",
|
| 277 |
+
"lstrip": false,
|
| 278 |
+
"normalized": false,
|
| 279 |
+
"rstrip": false,
|
| 280 |
+
"single_word": false,
|
| 281 |
+
"special": true
|
| 282 |
+
},
|
| 283 |
+
"291": {
|
| 284 |
+
"content": "<extra_id_32>",
|
| 285 |
+
"lstrip": false,
|
| 286 |
+
"normalized": false,
|
| 287 |
+
"rstrip": false,
|
| 288 |
+
"single_word": false,
|
| 289 |
+
"special": true
|
| 290 |
+
},
|
| 291 |
+
"292": {
|
| 292 |
+
"content": "<extra_id_33>",
|
| 293 |
+
"lstrip": false,
|
| 294 |
+
"normalized": false,
|
| 295 |
+
"rstrip": false,
|
| 296 |
+
"single_word": false,
|
| 297 |
+
"special": true
|
| 298 |
+
},
|
| 299 |
+
"293": {
|
| 300 |
+
"content": "<extra_id_34>",
|
| 301 |
+
"lstrip": false,
|
| 302 |
+
"normalized": false,
|
| 303 |
+
"rstrip": false,
|
| 304 |
+
"single_word": false,
|
| 305 |
+
"special": true
|
| 306 |
+
},
|
| 307 |
+
"294": {
|
| 308 |
+
"content": "<extra_id_35>",
|
| 309 |
+
"lstrip": false,
|
| 310 |
+
"normalized": false,
|
| 311 |
+
"rstrip": false,
|
| 312 |
+
"single_word": false,
|
| 313 |
+
"special": true
|
| 314 |
+
},
|
| 315 |
+
"295": {
|
| 316 |
+
"content": "<extra_id_36>",
|
| 317 |
+
"lstrip": false,
|
| 318 |
+
"normalized": false,
|
| 319 |
+
"rstrip": false,
|
| 320 |
+
"single_word": false,
|
| 321 |
+
"special": true
|
| 322 |
+
},
|
| 323 |
+
"296": {
|
| 324 |
+
"content": "<extra_id_37>",
|
| 325 |
+
"lstrip": false,
|
| 326 |
+
"normalized": false,
|
| 327 |
+
"rstrip": false,
|
| 328 |
+
"single_word": false,
|
| 329 |
+
"special": true
|
| 330 |
+
},
|
| 331 |
+
"297": {
|
| 332 |
+
"content": "<extra_id_38>",
|
| 333 |
+
"lstrip": false,
|
| 334 |
+
"normalized": false,
|
| 335 |
+
"rstrip": false,
|
| 336 |
+
"single_word": false,
|
| 337 |
+
"special": true
|
| 338 |
+
},
|
| 339 |
+
"298": {
|
| 340 |
+
"content": "<extra_id_39>",
|
| 341 |
+
"lstrip": false,
|
| 342 |
+
"normalized": false,
|
| 343 |
+
"rstrip": false,
|
| 344 |
+
"single_word": false,
|
| 345 |
+
"special": true
|
| 346 |
+
},
|
| 347 |
+
"299": {
|
| 348 |
+
"content": "<extra_id_40>",
|
| 349 |
+
"lstrip": false,
|
| 350 |
+
"normalized": false,
|
| 351 |
+
"rstrip": false,
|
| 352 |
+
"single_word": false,
|
| 353 |
+
"special": true
|
| 354 |
+
},
|
| 355 |
+
"300": {
|
| 356 |
+
"content": "<extra_id_41>",
|
| 357 |
+
"lstrip": false,
|
| 358 |
+
"normalized": false,
|
| 359 |
+
"rstrip": false,
|
| 360 |
+
"single_word": false,
|
| 361 |
+
"special": true
|
| 362 |
+
},
|
| 363 |
+
"301": {
|
| 364 |
+
"content": "<extra_id_42>",
|
| 365 |
+
"lstrip": false,
|
| 366 |
+
"normalized": false,
|
| 367 |
+
"rstrip": false,
|
| 368 |
+
"single_word": false,
|
| 369 |
+
"special": true
|
| 370 |
+
},
|
| 371 |
+
"302": {
|
| 372 |
+
"content": "<extra_id_43>",
|
| 373 |
+
"lstrip": false,
|
| 374 |
+
"normalized": false,
|
| 375 |
+
"rstrip": false,
|
| 376 |
+
"single_word": false,
|
| 377 |
+
"special": true
|
| 378 |
+
},
|
| 379 |
+
"303": {
|
| 380 |
+
"content": "<extra_id_44>",
|
| 381 |
+
"lstrip": false,
|
| 382 |
+
"normalized": false,
|
| 383 |
+
"rstrip": false,
|
| 384 |
+
"single_word": false,
|
| 385 |
+
"special": true
|
| 386 |
+
},
|
| 387 |
+
"304": {
|
| 388 |
+
"content": "<extra_id_45>",
|
| 389 |
+
"lstrip": false,
|
| 390 |
+
"normalized": false,
|
| 391 |
+
"rstrip": false,
|
| 392 |
+
"single_word": false,
|
| 393 |
+
"special": true
|
| 394 |
+
},
|
| 395 |
+
"305": {
|
| 396 |
+
"content": "<extra_id_46>",
|
| 397 |
+
"lstrip": false,
|
| 398 |
+
"normalized": false,
|
| 399 |
+
"rstrip": false,
|
| 400 |
+
"single_word": false,
|
| 401 |
+
"special": true
|
| 402 |
+
},
|
| 403 |
+
"306": {
|
| 404 |
+
"content": "<extra_id_47>",
|
| 405 |
+
"lstrip": false,
|
| 406 |
+
"normalized": false,
|
| 407 |
+
"rstrip": false,
|
| 408 |
+
"single_word": false,
|
| 409 |
+
"special": true
|
| 410 |
+
},
|
| 411 |
+
"307": {
|
| 412 |
+
"content": "<extra_id_48>",
|
| 413 |
+
"lstrip": false,
|
| 414 |
+
"normalized": false,
|
| 415 |
+
"rstrip": false,
|
| 416 |
+
"single_word": false,
|
| 417 |
+
"special": true
|
| 418 |
+
},
|
| 419 |
+
"308": {
|
| 420 |
+
"content": "<extra_id_49>",
|
| 421 |
+
"lstrip": false,
|
| 422 |
+
"normalized": false,
|
| 423 |
+
"rstrip": false,
|
| 424 |
+
"single_word": false,
|
| 425 |
+
"special": true
|
| 426 |
+
},
|
| 427 |
+
"309": {
|
| 428 |
+
"content": "<extra_id_50>",
|
| 429 |
+
"lstrip": false,
|
| 430 |
+
"normalized": false,
|
| 431 |
+
"rstrip": false,
|
| 432 |
+
"single_word": false,
|
| 433 |
+
"special": true
|
| 434 |
+
},
|
| 435 |
+
"310": {
|
| 436 |
+
"content": "<extra_id_51>",
|
| 437 |
+
"lstrip": false,
|
| 438 |
+
"normalized": false,
|
| 439 |
+
"rstrip": false,
|
| 440 |
+
"single_word": false,
|
| 441 |
+
"special": true
|
| 442 |
+
},
|
| 443 |
+
"311": {
|
| 444 |
+
"content": "<extra_id_52>",
|
| 445 |
+
"lstrip": false,
|
| 446 |
+
"normalized": false,
|
| 447 |
+
"rstrip": false,
|
| 448 |
+
"single_word": false,
|
| 449 |
+
"special": true
|
| 450 |
+
},
|
| 451 |
+
"312": {
|
| 452 |
+
"content": "<extra_id_53>",
|
| 453 |
+
"lstrip": false,
|
| 454 |
+
"normalized": false,
|
| 455 |
+
"rstrip": false,
|
| 456 |
+
"single_word": false,
|
| 457 |
+
"special": true
|
| 458 |
+
},
|
| 459 |
+
"313": {
|
| 460 |
+
"content": "<extra_id_54>",
|
| 461 |
+
"lstrip": false,
|
| 462 |
+
"normalized": false,
|
| 463 |
+
"rstrip": false,
|
| 464 |
+
"single_word": false,
|
| 465 |
+
"special": true
|
| 466 |
+
},
|
| 467 |
+
"314": {
|
| 468 |
+
"content": "<extra_id_55>",
|
| 469 |
+
"lstrip": false,
|
| 470 |
+
"normalized": false,
|
| 471 |
+
"rstrip": false,
|
| 472 |
+
"single_word": false,
|
| 473 |
+
"special": true
|
| 474 |
+
},
|
| 475 |
+
"315": {
|
| 476 |
+
"content": "<extra_id_56>",
|
| 477 |
+
"lstrip": false,
|
| 478 |
+
"normalized": false,
|
| 479 |
+
"rstrip": false,
|
| 480 |
+
"single_word": false,
|
| 481 |
+
"special": true
|
| 482 |
+
},
|
| 483 |
+
"316": {
|
| 484 |
+
"content": "<extra_id_57>",
|
| 485 |
+
"lstrip": false,
|
| 486 |
+
"normalized": false,
|
| 487 |
+
"rstrip": false,
|
| 488 |
+
"single_word": false,
|
| 489 |
+
"special": true
|
| 490 |
+
},
|
| 491 |
+
"317": {
|
| 492 |
+
"content": "<extra_id_58>",
|
| 493 |
+
"lstrip": false,
|
| 494 |
+
"normalized": false,
|
| 495 |
+
"rstrip": false,
|
| 496 |
+
"single_word": false,
|
| 497 |
+
"special": true
|
| 498 |
+
},
|
| 499 |
+
"318": {
|
| 500 |
+
"content": "<extra_id_59>",
|
| 501 |
+
"lstrip": false,
|
| 502 |
+
"normalized": false,
|
| 503 |
+
"rstrip": false,
|
| 504 |
+
"single_word": false,
|
| 505 |
+
"special": true
|
| 506 |
+
},
|
| 507 |
+
"319": {
|
| 508 |
+
"content": "<extra_id_60>",
|
| 509 |
+
"lstrip": false,
|
| 510 |
+
"normalized": false,
|
| 511 |
+
"rstrip": false,
|
| 512 |
+
"single_word": false,
|
| 513 |
+
"special": true
|
| 514 |
+
},
|
| 515 |
+
"320": {
|
| 516 |
+
"content": "<extra_id_61>",
|
| 517 |
+
"lstrip": false,
|
| 518 |
+
"normalized": false,
|
| 519 |
+
"rstrip": false,
|
| 520 |
+
"single_word": false,
|
| 521 |
+
"special": true
|
| 522 |
+
},
|
| 523 |
+
"321": {
|
| 524 |
+
"content": "<extra_id_62>",
|
| 525 |
+
"lstrip": false,
|
| 526 |
+
"normalized": false,
|
| 527 |
+
"rstrip": false,
|
| 528 |
+
"single_word": false,
|
| 529 |
+
"special": true
|
| 530 |
+
},
|
| 531 |
+
"322": {
|
| 532 |
+
"content": "<extra_id_63>",
|
| 533 |
+
"lstrip": false,
|
| 534 |
+
"normalized": false,
|
| 535 |
+
"rstrip": false,
|
| 536 |
+
"single_word": false,
|
| 537 |
+
"special": true
|
| 538 |
+
},
|
| 539 |
+
"323": {
|
| 540 |
+
"content": "<extra_id_64>",
|
| 541 |
+
"lstrip": false,
|
| 542 |
+
"normalized": false,
|
| 543 |
+
"rstrip": false,
|
| 544 |
+
"single_word": false,
|
| 545 |
+
"special": true
|
| 546 |
+
},
|
| 547 |
+
"324": {
|
| 548 |
+
"content": "<extra_id_65>",
|
| 549 |
+
"lstrip": false,
|
| 550 |
+
"normalized": false,
|
| 551 |
+
"rstrip": false,
|
| 552 |
+
"single_word": false,
|
| 553 |
+
"special": true
|
| 554 |
+
},
|
| 555 |
+
"325": {
|
| 556 |
+
"content": "<extra_id_66>",
|
| 557 |
+
"lstrip": false,
|
| 558 |
+
"normalized": false,
|
| 559 |
+
"rstrip": false,
|
| 560 |
+
"single_word": false,
|
| 561 |
+
"special": true
|
| 562 |
+
},
|
| 563 |
+
"326": {
|
| 564 |
+
"content": "<extra_id_67>",
|
| 565 |
+
"lstrip": false,
|
| 566 |
+
"normalized": false,
|
| 567 |
+
"rstrip": false,
|
| 568 |
+
"single_word": false,
|
| 569 |
+
"special": true
|
| 570 |
+
},
|
| 571 |
+
"327": {
|
| 572 |
+
"content": "<extra_id_68>",
|
| 573 |
+
"lstrip": false,
|
| 574 |
+
"normalized": false,
|
| 575 |
+
"rstrip": false,
|
| 576 |
+
"single_word": false,
|
| 577 |
+
"special": true
|
| 578 |
+
},
|
| 579 |
+
"328": {
|
| 580 |
+
"content": "<extra_id_69>",
|
| 581 |
+
"lstrip": false,
|
| 582 |
+
"normalized": false,
|
| 583 |
+
"rstrip": false,
|
| 584 |
+
"single_word": false,
|
| 585 |
+
"special": true
|
| 586 |
+
},
|
| 587 |
+
"329": {
|
| 588 |
+
"content": "<extra_id_70>",
|
| 589 |
+
"lstrip": false,
|
| 590 |
+
"normalized": false,
|
| 591 |
+
"rstrip": false,
|
| 592 |
+
"single_word": false,
|
| 593 |
+
"special": true
|
| 594 |
+
},
|
| 595 |
+
"330": {
|
| 596 |
+
"content": "<extra_id_71>",
|
| 597 |
+
"lstrip": false,
|
| 598 |
+
"normalized": false,
|
| 599 |
+
"rstrip": false,
|
| 600 |
+
"single_word": false,
|
| 601 |
+
"special": true
|
| 602 |
+
},
|
| 603 |
+
"331": {
|
| 604 |
+
"content": "<extra_id_72>",
|
| 605 |
+
"lstrip": false,
|
| 606 |
+
"normalized": false,
|
| 607 |
+
"rstrip": false,
|
| 608 |
+
"single_word": false,
|
| 609 |
+
"special": true
|
| 610 |
+
},
|
| 611 |
+
"332": {
|
| 612 |
+
"content": "<extra_id_73>",
|
| 613 |
+
"lstrip": false,
|
| 614 |
+
"normalized": false,
|
| 615 |
+
"rstrip": false,
|
| 616 |
+
"single_word": false,
|
| 617 |
+
"special": true
|
| 618 |
+
},
|
| 619 |
+
"333": {
|
| 620 |
+
"content": "<extra_id_74>",
|
| 621 |
+
"lstrip": false,
|
| 622 |
+
"normalized": false,
|
| 623 |
+
"rstrip": false,
|
| 624 |
+
"single_word": false,
|
| 625 |
+
"special": true
|
| 626 |
+
},
|
| 627 |
+
"334": {
|
| 628 |
+
"content": "<extra_id_75>",
|
| 629 |
+
"lstrip": false,
|
| 630 |
+
"normalized": false,
|
| 631 |
+
"rstrip": false,
|
| 632 |
+
"single_word": false,
|
| 633 |
+
"special": true
|
| 634 |
+
},
|
| 635 |
+
"335": {
|
| 636 |
+
"content": "<extra_id_76>",
|
| 637 |
+
"lstrip": false,
|
| 638 |
+
"normalized": false,
|
| 639 |
+
"rstrip": false,
|
| 640 |
+
"single_word": false,
|
| 641 |
+
"special": true
|
| 642 |
+
},
|
| 643 |
+
"336": {
|
| 644 |
+
"content": "<extra_id_77>",
|
| 645 |
+
"lstrip": false,
|
| 646 |
+
"normalized": false,
|
| 647 |
+
"rstrip": false,
|
| 648 |
+
"single_word": false,
|
| 649 |
+
"special": true
|
| 650 |
+
},
|
| 651 |
+
"337": {
|
| 652 |
+
"content": "<extra_id_78>",
|
| 653 |
+
"lstrip": false,
|
| 654 |
+
"normalized": false,
|
| 655 |
+
"rstrip": false,
|
| 656 |
+
"single_word": false,
|
| 657 |
+
"special": true
|
| 658 |
+
},
|
| 659 |
+
"338": {
|
| 660 |
+
"content": "<extra_id_79>",
|
| 661 |
+
"lstrip": false,
|
| 662 |
+
"normalized": false,
|
| 663 |
+
"rstrip": false,
|
| 664 |
+
"single_word": false,
|
| 665 |
+
"special": true
|
| 666 |
+
},
|
| 667 |
+
"339": {
|
| 668 |
+
"content": "<extra_id_80>",
|
| 669 |
+
"lstrip": false,
|
| 670 |
+
"normalized": false,
|
| 671 |
+
"rstrip": false,
|
| 672 |
+
"single_word": false,
|
| 673 |
+
"special": true
|
| 674 |
+
},
|
| 675 |
+
"340": {
|
| 676 |
+
"content": "<extra_id_81>",
|
| 677 |
+
"lstrip": false,
|
| 678 |
+
"normalized": false,
|
| 679 |
+
"rstrip": false,
|
| 680 |
+
"single_word": false,
|
| 681 |
+
"special": true
|
| 682 |
+
},
|
| 683 |
+
"341": {
|
| 684 |
+
"content": "<extra_id_82>",
|
| 685 |
+
"lstrip": false,
|
| 686 |
+
"normalized": false,
|
| 687 |
+
"rstrip": false,
|
| 688 |
+
"single_word": false,
|
| 689 |
+
"special": true
|
| 690 |
+
},
|
| 691 |
+
"342": {
|
| 692 |
+
"content": "<extra_id_83>",
|
| 693 |
+
"lstrip": false,
|
| 694 |
+
"normalized": false,
|
| 695 |
+
"rstrip": false,
|
| 696 |
+
"single_word": false,
|
| 697 |
+
"special": true
|
| 698 |
+
},
|
| 699 |
+
"343": {
|
| 700 |
+
"content": "<extra_id_84>",
|
| 701 |
+
"lstrip": false,
|
| 702 |
+
"normalized": false,
|
| 703 |
+
"rstrip": false,
|
| 704 |
+
"single_word": false,
|
| 705 |
+
"special": true
|
| 706 |
+
},
|
| 707 |
+
"344": {
|
| 708 |
+
"content": "<extra_id_85>",
|
| 709 |
+
"lstrip": false,
|
| 710 |
+
"normalized": false,
|
| 711 |
+
"rstrip": false,
|
| 712 |
+
"single_word": false,
|
| 713 |
+
"special": true
|
| 714 |
+
},
|
| 715 |
+
"345": {
|
| 716 |
+
"content": "<extra_id_86>",
|
| 717 |
+
"lstrip": false,
|
| 718 |
+
"normalized": false,
|
| 719 |
+
"rstrip": false,
|
| 720 |
+
"single_word": false,
|
| 721 |
+
"special": true
|
| 722 |
+
},
|
| 723 |
+
"346": {
|
| 724 |
+
"content": "<extra_id_87>",
|
| 725 |
+
"lstrip": false,
|
| 726 |
+
"normalized": false,
|
| 727 |
+
"rstrip": false,
|
| 728 |
+
"single_word": false,
|
| 729 |
+
"special": true
|
| 730 |
+
},
|
| 731 |
+
"347": {
|
| 732 |
+
"content": "<extra_id_88>",
|
| 733 |
+
"lstrip": false,
|
| 734 |
+
"normalized": false,
|
| 735 |
+
"rstrip": false,
|
| 736 |
+
"single_word": false,
|
| 737 |
+
"special": true
|
| 738 |
+
},
|
| 739 |
+
"348": {
|
| 740 |
+
"content": "<extra_id_89>",
|
| 741 |
+
"lstrip": false,
|
| 742 |
+
"normalized": false,
|
| 743 |
+
"rstrip": false,
|
| 744 |
+
"single_word": false,
|
| 745 |
+
"special": true
|
| 746 |
+
},
|
| 747 |
+
"349": {
|
| 748 |
+
"content": "<extra_id_90>",
|
| 749 |
+
"lstrip": false,
|
| 750 |
+
"normalized": false,
|
| 751 |
+
"rstrip": false,
|
| 752 |
+
"single_word": false,
|
| 753 |
+
"special": true
|
| 754 |
+
},
|
| 755 |
+
"350": {
|
| 756 |
+
"content": "<extra_id_91>",
|
| 757 |
+
"lstrip": false,
|
| 758 |
+
"normalized": false,
|
| 759 |
+
"rstrip": false,
|
| 760 |
+
"single_word": false,
|
| 761 |
+
"special": true
|
| 762 |
+
},
|
| 763 |
+
"351": {
|
| 764 |
+
"content": "<extra_id_92>",
|
| 765 |
+
"lstrip": false,
|
| 766 |
+
"normalized": false,
|
| 767 |
+
"rstrip": false,
|
| 768 |
+
"single_word": false,
|
| 769 |
+
"special": true
|
| 770 |
+
},
|
| 771 |
+
"352": {
|
| 772 |
+
"content": "<extra_id_93>",
|
| 773 |
+
"lstrip": false,
|
| 774 |
+
"normalized": false,
|
| 775 |
+
"rstrip": false,
|
| 776 |
+
"single_word": false,
|
| 777 |
+
"special": true
|
| 778 |
+
},
|
| 779 |
+
"353": {
|
| 780 |
+
"content": "<extra_id_94>",
|
| 781 |
+
"lstrip": false,
|
| 782 |
+
"normalized": false,
|
| 783 |
+
"rstrip": false,
|
| 784 |
+
"single_word": false,
|
| 785 |
+
"special": true
|
| 786 |
+
},
|
| 787 |
+
"354": {
|
| 788 |
+
"content": "<extra_id_95>",
|
| 789 |
+
"lstrip": false,
|
| 790 |
+
"normalized": false,
|
| 791 |
+
"rstrip": false,
|
| 792 |
+
"single_word": false,
|
| 793 |
+
"special": true
|
| 794 |
+
},
|
| 795 |
+
"355": {
|
| 796 |
+
"content": "<extra_id_96>",
|
| 797 |
+
"lstrip": false,
|
| 798 |
+
"normalized": false,
|
| 799 |
+
"rstrip": false,
|
| 800 |
+
"single_word": false,
|
| 801 |
+
"special": true
|
| 802 |
+
},
|
| 803 |
+
"356": {
|
| 804 |
+
"content": "<extra_id_97>",
|
| 805 |
+
"lstrip": false,
|
| 806 |
+
"normalized": false,
|
| 807 |
+
"rstrip": false,
|
| 808 |
+
"single_word": false,
|
| 809 |
+
"special": true
|
| 810 |
+
},
|
| 811 |
+
"357": {
|
| 812 |
+
"content": "<extra_id_98>",
|
| 813 |
+
"lstrip": false,
|
| 814 |
+
"normalized": false,
|
| 815 |
+
"rstrip": false,
|
| 816 |
+
"single_word": false,
|
| 817 |
+
"special": true
|
| 818 |
+
},
|
| 819 |
+
"358": {
|
| 820 |
+
"content": "<extra_id_99>",
|
| 821 |
+
"lstrip": false,
|
| 822 |
+
"normalized": false,
|
| 823 |
+
"rstrip": false,
|
| 824 |
+
"single_word": false,
|
| 825 |
+
"special": true
|
| 826 |
+
},
|
| 827 |
+
"359": {
|
| 828 |
+
"content": "<extra_id_100>",
|
| 829 |
+
"lstrip": false,
|
| 830 |
+
"normalized": false,
|
| 831 |
+
"rstrip": false,
|
| 832 |
+
"single_word": false,
|
| 833 |
+
"special": true
|
| 834 |
+
},
|
| 835 |
+
"360": {
|
| 836 |
+
"content": "<extra_id_101>",
|
| 837 |
+
"lstrip": false,
|
| 838 |
+
"normalized": false,
|
| 839 |
+
"rstrip": false,
|
| 840 |
+
"single_word": false,
|
| 841 |
+
"special": true
|
| 842 |
+
},
|
| 843 |
+
"361": {
|
| 844 |
+
"content": "<extra_id_102>",
|
| 845 |
+
"lstrip": false,
|
| 846 |
+
"normalized": false,
|
| 847 |
+
"rstrip": false,
|
| 848 |
+
"single_word": false,
|
| 849 |
+
"special": true
|
| 850 |
+
},
|
| 851 |
+
"362": {
|
| 852 |
+
"content": "<extra_id_103>",
|
| 853 |
+
"lstrip": false,
|
| 854 |
+
"normalized": false,
|
| 855 |
+
"rstrip": false,
|
| 856 |
+
"single_word": false,
|
| 857 |
+
"special": true
|
| 858 |
+
},
|
| 859 |
+
"363": {
|
| 860 |
+
"content": "<extra_id_104>",
|
| 861 |
+
"lstrip": false,
|
| 862 |
+
"normalized": false,
|
| 863 |
+
"rstrip": false,
|
| 864 |
+
"single_word": false,
|
| 865 |
+
"special": true
|
| 866 |
+
},
|
| 867 |
+
"364": {
|
| 868 |
+
"content": "<extra_id_105>",
|
| 869 |
+
"lstrip": false,
|
| 870 |
+
"normalized": false,
|
| 871 |
+
"rstrip": false,
|
| 872 |
+
"single_word": false,
|
| 873 |
+
"special": true
|
| 874 |
+
},
|
| 875 |
+
"365": {
|
| 876 |
+
"content": "<extra_id_106>",
|
| 877 |
+
"lstrip": false,
|
| 878 |
+
"normalized": false,
|
| 879 |
+
"rstrip": false,
|
| 880 |
+
"single_word": false,
|
| 881 |
+
"special": true
|
| 882 |
+
},
|
| 883 |
+
"366": {
|
| 884 |
+
"content": "<extra_id_107>",
|
| 885 |
+
"lstrip": false,
|
| 886 |
+
"normalized": false,
|
| 887 |
+
"rstrip": false,
|
| 888 |
+
"single_word": false,
|
| 889 |
+
"special": true
|
| 890 |
+
},
|
| 891 |
+
"367": {
|
| 892 |
+
"content": "<extra_id_108>",
|
| 893 |
+
"lstrip": false,
|
| 894 |
+
"normalized": false,
|
| 895 |
+
"rstrip": false,
|
| 896 |
+
"single_word": false,
|
| 897 |
+
"special": true
|
| 898 |
+
},
|
| 899 |
+
"368": {
|
| 900 |
+
"content": "<extra_id_109>",
|
| 901 |
+
"lstrip": false,
|
| 902 |
+
"normalized": false,
|
| 903 |
+
"rstrip": false,
|
| 904 |
+
"single_word": false,
|
| 905 |
+
"special": true
|
| 906 |
+
},
|
| 907 |
+
"369": {
|
| 908 |
+
"content": "<extra_id_110>",
|
| 909 |
+
"lstrip": false,
|
| 910 |
+
"normalized": false,
|
| 911 |
+
"rstrip": false,
|
| 912 |
+
"single_word": false,
|
| 913 |
+
"special": true
|
| 914 |
+
},
|
| 915 |
+
"370": {
|
| 916 |
+
"content": "<extra_id_111>",
|
| 917 |
+
"lstrip": false,
|
| 918 |
+
"normalized": false,
|
| 919 |
+
"rstrip": false,
|
| 920 |
+
"single_word": false,
|
| 921 |
+
"special": true
|
| 922 |
+
},
|
| 923 |
+
"371": {
|
| 924 |
+
"content": "<extra_id_112>",
|
| 925 |
+
"lstrip": false,
|
| 926 |
+
"normalized": false,
|
| 927 |
+
"rstrip": false,
|
| 928 |
+
"single_word": false,
|
| 929 |
+
"special": true
|
| 930 |
+
},
|
| 931 |
+
"372": {
|
| 932 |
+
"content": "<extra_id_113>",
|
| 933 |
+
"lstrip": false,
|
| 934 |
+
"normalized": false,
|
| 935 |
+
"rstrip": false,
|
| 936 |
+
"single_word": false,
|
| 937 |
+
"special": true
|
| 938 |
+
},
|
| 939 |
+
"373": {
|
| 940 |
+
"content": "<extra_id_114>",
|
| 941 |
+
"lstrip": false,
|
| 942 |
+
"normalized": false,
|
| 943 |
+
"rstrip": false,
|
| 944 |
+
"single_word": false,
|
| 945 |
+
"special": true
|
| 946 |
+
},
|
| 947 |
+
"374": {
|
| 948 |
+
"content": "<extra_id_115>",
|
| 949 |
+
"lstrip": false,
|
| 950 |
+
"normalized": false,
|
| 951 |
+
"rstrip": false,
|
| 952 |
+
"single_word": false,
|
| 953 |
+
"special": true
|
| 954 |
+
},
|
| 955 |
+
"375": {
|
| 956 |
+
"content": "<extra_id_116>",
|
| 957 |
+
"lstrip": false,
|
| 958 |
+
"normalized": false,
|
| 959 |
+
"rstrip": false,
|
| 960 |
+
"single_word": false,
|
| 961 |
+
"special": true
|
| 962 |
+
},
|
| 963 |
+
"376": {
|
| 964 |
+
"content": "<extra_id_117>",
|
| 965 |
+
"lstrip": false,
|
| 966 |
+
"normalized": false,
|
| 967 |
+
"rstrip": false,
|
| 968 |
+
"single_word": false,
|
| 969 |
+
"special": true
|
| 970 |
+
},
|
| 971 |
+
"377": {
|
| 972 |
+
"content": "<extra_id_118>",
|
| 973 |
+
"lstrip": false,
|
| 974 |
+
"normalized": false,
|
| 975 |
+
"rstrip": false,
|
| 976 |
+
"single_word": false,
|
| 977 |
+
"special": true
|
| 978 |
+
},
|
| 979 |
+
"378": {
|
| 980 |
+
"content": "<extra_id_119>",
|
| 981 |
+
"lstrip": false,
|
| 982 |
+
"normalized": false,
|
| 983 |
+
"rstrip": false,
|
| 984 |
+
"single_word": false,
|
| 985 |
+
"special": true
|
| 986 |
+
},
|
| 987 |
+
"379": {
|
| 988 |
+
"content": "<extra_id_120>",
|
| 989 |
+
"lstrip": false,
|
| 990 |
+
"normalized": false,
|
| 991 |
+
"rstrip": false,
|
| 992 |
+
"single_word": false,
|
| 993 |
+
"special": true
|
| 994 |
+
},
|
| 995 |
+
"380": {
|
| 996 |
+
"content": "<extra_id_121>",
|
| 997 |
+
"lstrip": false,
|
| 998 |
+
"normalized": false,
|
| 999 |
+
"rstrip": false,
|
| 1000 |
+
"single_word": false,
|
| 1001 |
+
"special": true
|
| 1002 |
+
},
|
| 1003 |
+
"381": {
|
| 1004 |
+
"content": "<extra_id_122>",
|
| 1005 |
+
"lstrip": false,
|
| 1006 |
+
"normalized": false,
|
| 1007 |
+
"rstrip": false,
|
| 1008 |
+
"single_word": false,
|
| 1009 |
+
"special": true
|
| 1010 |
+
},
|
| 1011 |
+
"382": {
|
| 1012 |
+
"content": "<extra_id_123>",
|
| 1013 |
+
"lstrip": false,
|
| 1014 |
+
"normalized": false,
|
| 1015 |
+
"rstrip": false,
|
| 1016 |
+
"single_word": false,
|
| 1017 |
+
"special": true
|
| 1018 |
+
},
|
| 1019 |
+
"383": {
|
| 1020 |
+
"content": "<extra_id_124>",
|
| 1021 |
+
"lstrip": false,
|
| 1022 |
+
"normalized": false,
|
| 1023 |
+
"rstrip": false,
|
| 1024 |
+
"single_word": false,
|
| 1025 |
+
"special": true
|
| 1026 |
+
}
|
| 1027 |
+
},
|
| 1028 |
+
"additional_special_tokens": [
|
| 1029 |
+
"<extra_id_0>",
|
| 1030 |
+
"<extra_id_1>",
|
| 1031 |
+
"<extra_id_2>",
|
| 1032 |
+
"<extra_id_3>",
|
| 1033 |
+
"<extra_id_4>",
|
| 1034 |
+
"<extra_id_5>",
|
| 1035 |
+
"<extra_id_6>",
|
| 1036 |
+
"<extra_id_7>",
|
| 1037 |
+
"<extra_id_8>",
|
| 1038 |
+
"<extra_id_9>",
|
| 1039 |
+
"<extra_id_10>",
|
| 1040 |
+
"<extra_id_11>",
|
| 1041 |
+
"<extra_id_12>",
|
| 1042 |
+
"<extra_id_13>",
|
| 1043 |
+
"<extra_id_14>",
|
| 1044 |
+
"<extra_id_15>",
|
| 1045 |
+
"<extra_id_16>",
|
| 1046 |
+
"<extra_id_17>",
|
| 1047 |
+
"<extra_id_18>",
|
| 1048 |
+
"<extra_id_19>",
|
| 1049 |
+
"<extra_id_20>",
|
| 1050 |
+
"<extra_id_21>",
|
| 1051 |
+
"<extra_id_22>",
|
| 1052 |
+
"<extra_id_23>",
|
| 1053 |
+
"<extra_id_24>",
|
| 1054 |
+
"<extra_id_25>",
|
| 1055 |
+
"<extra_id_26>",
|
| 1056 |
+
"<extra_id_27>",
|
| 1057 |
+
"<extra_id_28>",
|
| 1058 |
+
"<extra_id_29>",
|
| 1059 |
+
"<extra_id_30>",
|
| 1060 |
+
"<extra_id_31>",
|
| 1061 |
+
"<extra_id_32>",
|
| 1062 |
+
"<extra_id_33>",
|
| 1063 |
+
"<extra_id_34>",
|
| 1064 |
+
"<extra_id_35>",
|
| 1065 |
+
"<extra_id_36>",
|
| 1066 |
+
"<extra_id_37>",
|
| 1067 |
+
"<extra_id_38>",
|
| 1068 |
+
"<extra_id_39>",
|
| 1069 |
+
"<extra_id_40>",
|
| 1070 |
+
"<extra_id_41>",
|
| 1071 |
+
"<extra_id_42>",
|
| 1072 |
+
"<extra_id_43>",
|
| 1073 |
+
"<extra_id_44>",
|
| 1074 |
+
"<extra_id_45>",
|
| 1075 |
+
"<extra_id_46>",
|
| 1076 |
+
"<extra_id_47>",
|
| 1077 |
+
"<extra_id_48>",
|
| 1078 |
+
"<extra_id_49>",
|
| 1079 |
+
"<extra_id_50>",
|
| 1080 |
+
"<extra_id_51>",
|
| 1081 |
+
"<extra_id_52>",
|
| 1082 |
+
"<extra_id_53>",
|
| 1083 |
+
"<extra_id_54>",
|
| 1084 |
+
"<extra_id_55>",
|
| 1085 |
+
"<extra_id_56>",
|
| 1086 |
+
"<extra_id_57>",
|
| 1087 |
+
"<extra_id_58>",
|
| 1088 |
+
"<extra_id_59>",
|
| 1089 |
+
"<extra_id_60>",
|
| 1090 |
+
"<extra_id_61>",
|
| 1091 |
+
"<extra_id_62>",
|
| 1092 |
+
"<extra_id_63>",
|
| 1093 |
+
"<extra_id_64>",
|
| 1094 |
+
"<extra_id_65>",
|
| 1095 |
+
"<extra_id_66>",
|
| 1096 |
+
"<extra_id_67>",
|
| 1097 |
+
"<extra_id_68>",
|
| 1098 |
+
"<extra_id_69>",
|
| 1099 |
+
"<extra_id_70>",
|
| 1100 |
+
"<extra_id_71>",
|
| 1101 |
+
"<extra_id_72>",
|
| 1102 |
+
"<extra_id_73>",
|
| 1103 |
+
"<extra_id_74>",
|
| 1104 |
+
"<extra_id_75>",
|
| 1105 |
+
"<extra_id_76>",
|
| 1106 |
+
"<extra_id_77>",
|
| 1107 |
+
"<extra_id_78>",
|
| 1108 |
+
"<extra_id_79>",
|
| 1109 |
+
"<extra_id_80>",
|
| 1110 |
+
"<extra_id_81>",
|
| 1111 |
+
"<extra_id_82>",
|
| 1112 |
+
"<extra_id_83>",
|
| 1113 |
+
"<extra_id_84>",
|
| 1114 |
+
"<extra_id_85>",
|
| 1115 |
+
"<extra_id_86>",
|
| 1116 |
+
"<extra_id_87>",
|
| 1117 |
+
"<extra_id_88>",
|
| 1118 |
+
"<extra_id_89>",
|
| 1119 |
+
"<extra_id_90>",
|
| 1120 |
+
"<extra_id_91>",
|
| 1121 |
+
"<extra_id_92>",
|
| 1122 |
+
"<extra_id_93>",
|
| 1123 |
+
"<extra_id_94>",
|
| 1124 |
+
"<extra_id_95>",
|
| 1125 |
+
"<extra_id_96>",
|
| 1126 |
+
"<extra_id_97>",
|
| 1127 |
+
"<extra_id_98>",
|
| 1128 |
+
"<extra_id_99>",
|
| 1129 |
+
"<extra_id_100>",
|
| 1130 |
+
"<extra_id_101>",
|
| 1131 |
+
"<extra_id_102>",
|
| 1132 |
+
"<extra_id_103>",
|
| 1133 |
+
"<extra_id_104>",
|
| 1134 |
+
"<extra_id_105>",
|
| 1135 |
+
"<extra_id_106>",
|
| 1136 |
+
"<extra_id_107>",
|
| 1137 |
+
"<extra_id_108>",
|
| 1138 |
+
"<extra_id_109>",
|
| 1139 |
+
"<extra_id_110>",
|
| 1140 |
+
"<extra_id_111>",
|
| 1141 |
+
"<extra_id_112>",
|
| 1142 |
+
"<extra_id_113>",
|
| 1143 |
+
"<extra_id_114>",
|
| 1144 |
+
"<extra_id_115>",
|
| 1145 |
+
"<extra_id_116>",
|
| 1146 |
+
"<extra_id_117>",
|
| 1147 |
+
"<extra_id_118>",
|
| 1148 |
+
"<extra_id_119>",
|
| 1149 |
+
"<extra_id_120>",
|
| 1150 |
+
"<extra_id_121>",
|
| 1151 |
+
"<extra_id_122>",
|
| 1152 |
+
"<extra_id_123>",
|
| 1153 |
+
"<extra_id_124>"
|
| 1154 |
+
],
|
| 1155 |
+
"clean_up_tokenization_spaces": false,
|
| 1156 |
+
"eos_token": "</s>",
|
| 1157 |
+
"extra_ids": 0,
|
| 1158 |
+
"extra_special_tokens": {},
|
| 1159 |
+
"model_max_length": 1000000000000000019884624838656,
|
| 1160 |
+
"pad_token": "<pad>",
|
| 1161 |
+
"tokenizer_class": "ByT5Tokenizer",
|
| 1162 |
+
"unk_token": "<unk>"
|
| 1163 |
+
}
|
checkpoints/flash/flash_dpo/args.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
{"cmd": "train", "lm": "/home/dev/flash/runs/flash_lm/best.pt", "out": "/home/dev/flash/runs/flash_dpo", "shard": "0/1", "k": 4, "lr": 1e-06, "beta": 0.1, "sft": 0.1, "bs": 8, "epochs": 2}
|
checkpoints/flash/flash_dpo/best.pt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f59a6fc0dacc331844cf8b513ec99e4d5c75f2583115037c8d38ba9ff7e3a307
|
| 3 |
+
size 2047760470
|
checkpoints/flash/flash_dpo/config.json
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"engine": "cosyvoice3",
|
| 3 |
+
"base": "FunAudioLLM/Fun-CosyVoice3-0.5B-2512",
|
| 4 |
+
"rate": "normal",
|
| 5 |
+
"sampler": "silexcap",
|
| 6 |
+
"one_pass": true,
|
| 7 |
+
"sha256_best_pt": "f59a6fc0dacc331844cf8b513ec99e4d5c75f2583115037c8d38ba9ff7e3a307",
|
| 8 |
+
"training": "Flash SFT (CV3 LM, Phase 3 licensed manifest re-weighted + IgboSynCorp pseudo-transcripts) then DPO: 1,206 preference pairs, 286 steps, beta 0.1, lr 1e-6, val pref-acc 0.65"
|
| 9 |
+
}
|
checkpoints/flash/flash_dpo/log.jsonl
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"step": 0, "val": {"acc": 0.0, "margin": 0.0}}
|
| 2 |
+
{"step": 10, "of": 286, "loss": 0.9068, "acc": 0.625, "margin": 0.046, "gn": 57.21, "min": 0.1}
|
| 3 |
+
{"step": 20, "of": 286, "loss": 0.9388, "acc": 0.5, "margin": -0.002, "gn": 66.55, "min": 0.1}
|
| 4 |
+
{"step": 30, "of": 286, "loss": 0.9699, "acc": 0.375, "margin": -0.035, "gn": 61.96, "min": 0.2}
|
| 5 |
+
{"step": 40, "of": 286, "loss": 0.938, "acc": 0.375, "margin": 0.011, "gn": 63.67, "min": 0.3}
|
| 6 |
+
{"step": 50, "of": 286, "loss": 0.8633, "acc": 0.875, "margin": 0.15, "gn": 52.25, "min": 0.3}
|
| 7 |
+
{"step": 60, "of": 286, "loss": 0.939, "acc": 0.625, "margin": 0.002, "gn": 63.83, "min": 0.4}
|
| 8 |
+
{"step": 70, "of": 286, "loss": 0.8483, "acc": 0.75, "margin": 0.189, "gn": 69.48, "min": 0.4}
|
| 9 |
+
{"step": 80, "of": 286, "loss": 1.0202, "acc": 0.375, "margin": -0.139, "gn": 80.15, "min": 0.5}
|
| 10 |
+
{"step": 90, "of": 286, "loss": 0.8866, "acc": 0.625, "margin": 0.142, "gn": 59.47, "min": 0.5}
|
| 11 |
+
{"step": 100, "of": 286, "loss": 0.8947, "acc": 0.625, "margin": 0.134, "gn": 60.78, "min": 0.6}
|
| 12 |
+
{"step": 110, "of": 286, "loss": 0.9459, "acc": 0.5, "margin": 0.027, "gn": 66.75, "min": 0.6}
|
| 13 |
+
{"step": 120, "of": 286, "loss": 1.0125, "acc": 0.375, "margin": -0.11, "gn": 65.48, "min": 0.7}
|
| 14 |
+
{"step": 130, "of": 286, "loss": 0.8009, "acc": 0.75, "margin": 0.365, "gn": 50.92, "min": 0.8}
|
| 15 |
+
{"step": 140, "of": 286, "loss": 0.8328, "acc": 0.75, "margin": 0.277, "gn": 60.21, "min": 0.8}
|
| 16 |
+
{"epoch": 1, "step": 143, "val": {"acc": 0.6, "margin": 0.15548671048794252}}
|
| 17 |
+
{"step": 150, "of": 286, "loss": 0.5242, "acc": 1.0, "margin": 1.345, "gn": 31.71, "min": 0.9}
|
| 18 |
+
{"step": 160, "of": 286, "loss": 0.476, "acc": 1.0, "margin": 1.509, "gn": 28.95, "min": 0.9}
|
| 19 |
+
{"step": 170, "of": 286, "loss": 0.5501, "acc": 1.0, "margin": 1.171, "gn": 29.98, "min": 1.0}
|
| 20 |
+
{"step": 180, "of": 286, "loss": 0.474, "acc": 1.0, "margin": 1.492, "gn": 26.95, "min": 1.0}
|
| 21 |
+
{"step": 190, "of": 286, "loss": 0.5711, "acc": 1.0, "margin": 1.032, "gn": 34.13, "min": 1.1}
|
| 22 |
+
{"step": 200, "of": 286, "loss": 0.5283, "acc": 1.0, "margin": 1.181, "gn": 32.39, "min": 1.1}
|
| 23 |
+
{"step": 210, "of": 286, "loss": 0.6212, "acc": 0.875, "margin": 0.86, "gn": 36.1, "min": 1.2}
|
| 24 |
+
{"step": 220, "of": 286, "loss": 0.5229, "acc": 1.0, "margin": 1.227, "gn": 32.65, "min": 1.2}
|
| 25 |
+
{"step": 230, "of": 286, "loss": 0.5555, "acc": 1.0, "margin": 1.367, "gn": 35.05, "min": 1.3}
|
| 26 |
+
{"step": 240, "of": 286, "loss": 0.5312, "acc": 1.0, "margin": 1.314, "gn": 36.6, "min": 1.3}
|
| 27 |
+
{"step": 250, "of": 286, "loss": 0.493, "acc": 1.0, "margin": 1.513, "gn": 28.32, "min": 1.3}
|
| 28 |
+
{"step": 260, "of": 286, "loss": 0.5076, "acc": 1.0, "margin": 1.31, "gn": 25.17, "min": 1.4}
|
| 29 |
+
{"step": 270, "of": 286, "loss": 0.434, "acc": 1.0, "margin": 1.739, "gn": 23.64, "min": 1.4}
|
| 30 |
+
{"step": 280, "of": 286, "loss": 0.4263, "acc": 1.0, "margin": 1.907, "gn": 24.99, "min": 1.5}
|
| 31 |
+
{"epoch": 2, "step": 286, "val": {"acc": 0.65, "margin": 0.17853533582141}}
|
checkpoints/flash/flash_dpo/spk2id.json
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
flash_lm.py
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dynamic Accent Flash: CosyVoice3 (Fun-CosyVoice3-0.5B-2512, Apache-2.0) LM fine-tune + synthesis.
|
| 2 |
+
|
| 3 |
+
Same additions as Phase 2/3 (per-token language embedding, learned speaker token after the text, rate embedding added to
|
| 4 |
+
the speaker vector, GRL speaker classifier on text positions, in-context same-speaker prompt p=0.5), ported to the CV3 LM:
|
| 5 |
+
seq = [sos, "You are a helpful assistant.<|endofprompt|>", (prompt text) text, spk(+rate), task, (prompt speech) speech, eos]
|
| 6 |
+
sos/task live in speech_embedding (CV3), eos = speech_token_size+1. Targets are CV3 speech tokens (s3v3.*).
|
| 7 |
+
Flow (DiT) + HiFT = CV3 base, zero-shot prompted with the voice clip (no flow fine-tune).
|
| 8 |
+
|
| 9 |
+
python flash_lm.py lm --out ~/flash/runs/flash_lm --max_steps 12000 --minutes 75
|
| 10 |
+
python flash_lm.py gen --lm CKPT --out DIR [--voice anchor|waxal_ibo_5|waxal_yor_5] [--rate normal] [--rows ROWS]
|
| 11 |
+
|
| 12 |
+
Release note: in this repo use `infer.py --version flash` (it wraps Synth below). Training needs the Phase 3 data
|
| 13 |
+
manifest, which is not shipped; the training code is included for reference. Paths come from COSYVOICE_REPO (CosyVoice
|
| 14 |
+
clone with CosyVoice3 support) and CV3_DIR (Fun-CosyVoice3-0.5B-2512 snapshot).
|
| 15 |
+
"""
|
| 16 |
+
import argparse, json, math, os, random, sys, time, inspect
|
| 17 |
+
import numpy as np, torch, torch.nn as nn, torch.nn.functional as F, soundfile as sf, librosa
|
| 18 |
+
|
| 19 |
+
HOME = os.path.expanduser("~")
|
| 20 |
+
_HERE = os.path.dirname(os.path.abspath(__file__))
|
| 21 |
+
_CV = os.environ.get("COSYVOICE_REPO") or (f"{_HERE}/CosyVoice" if os.path.isdir(f"{_HERE}/CosyVoice") else f"{HOME}/CosyVoice")
|
| 22 |
+
sys.path[:0] = [_CV, f"{_CV}/third_party/Matcha-TTS", f"{_HERE}/code", f"{HOME}/da"]
|
| 23 |
+
from da.text import segments # noqa: E402
|
| 24 |
+
from da.model import grad_reverse # noqa: E402
|
| 25 |
+
|
| 26 |
+
CV3 = os.environ.get("CV3_DIR") or (f"{_HERE}/pretrained/Fun-CosyVoice3-0.5B-2512" if os.path.isdir(f"{_HERE}/pretrained/Fun-CosyVoice3-0.5B-2512") else f"{HOME}/models/Fun-CosyVoice3-0.5B-2512")
|
| 27 |
+
LANGS = ["eng", "ibo", "hau", "yor", "pcm"]
|
| 28 |
+
L2I = {l: i for i, l in enumerate(LANGS)}
|
| 29 |
+
RATES = [None, "very slow", "slow", "normal", "fast", "very fast"]
|
| 30 |
+
R2I = {r: i for i, r in enumerate(RATES)}
|
| 31 |
+
TAGS = ("[pause]", "[breath]", "[quick_breath]", "[laughter]")
|
| 32 |
+
SIL = {1, 2, 28, 29, 55, 248, 494, 2241, 2242, 2322, 2323} # CV3 FSQ silent/breath tokens (cosyvoice/cli/model.py)
|
| 33 |
+
ANCHOR = "waxal_yor_4"
|
| 34 |
+
NEW = ["waxal", "igboapi", "open_bible_igbo", "naijas2st_igbo", "igbosyncorp"]
|
| 35 |
+
MAN = f"{HOME}/p3t/manifest_p3.jsonl"
|
| 36 |
+
PDIR = os.environ.get("DA_PROMPTS") or (f"{_HERE}/prompts" if os.path.isdir(f"{_HERE}/prompts") else f"{HOME}/hf_test/prompts")
|
| 37 |
+
VOICES = {
|
| 38 |
+
"anchor": dict(wav=f"{PDIR}/clip0_waxal_yor_yor_1258.wav" if os.path.exists(f"{PDIR}/clip0_waxal_yor_yor_1258.wav")
|
| 39 |
+
else f"{PDIR}/waxal_yor_yor_1258.wav", spk=ANCHOR),
|
| 40 |
+
"waxal_ibo_5": dict(wav=f"{PDIR}/voice_waxal_ibo_5.wav", spk="waxal_ibo_5"),
|
| 41 |
+
"waxal_yor_5": dict(wav=f"{PDIR}/voice_waxal_yor_5.wav", spk="waxal_yor_5"),
|
| 42 |
+
}
|
| 43 |
+
# Flash source re-weighting on top of the Phase 3 manifest weight: less Bible narration and slow phone/dictionary reads
|
| 44 |
+
FLASH_W = {"open_bible_igbo": 0.4, "bible_hau": 0.5, "bible_yor": 0.5, "igboapi": 0.6, "naijas2st_igbo": 0.6,
|
| 45 |
+
"igbosyn_pseudo": 1.0}
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def strip_tags(t):
|
| 49 |
+
for g in TAGS:
|
| 50 |
+
t = t.replace(g, " ")
|
| 51 |
+
return " ".join(t.split()).replace(" ,", ",").replace(" .", ".")
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def _sf_load_wav(wav, target_sr, min_sr=16000):
|
| 55 |
+
y, sr = sf.read(wav, dtype="float32", always_2d=True)
|
| 56 |
+
y = y.mean(1)
|
| 57 |
+
if sr != target_sr:
|
| 58 |
+
y = librosa.resample(y, orig_sr=sr, target_sr=target_sr)
|
| 59 |
+
return torch.from_numpy(y)[None]
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def load_cv3():
|
| 63 |
+
import cosyvoice.utils.file_utils as fu
|
| 64 |
+
fu.load_wav = _sf_load_wav
|
| 65 |
+
import cosyvoice.cli.frontend as cf
|
| 66 |
+
cf.load_wav = _sf_load_wav
|
| 67 |
+
from cosyvoice.cli.cosyvoice import CosyVoice3
|
| 68 |
+
kw = dict(load_jit=False, load_trt=False, fp16=False)
|
| 69 |
+
sig = inspect.signature(CosyVoice3.__init__).parameters
|
| 70 |
+
return CosyVoice3(CV3, **{k: v for k, v in kw.items() if k in sig})
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
class Tok:
|
| 74 |
+
def __init__(self, cosy):
|
| 75 |
+
self.t = cosy.frontend.tokenizer
|
| 76 |
+
self.prefix = self.t.encode("You are a helpful assistant.") + [151646]
|
| 77 |
+
self.cache = {}
|
| 78 |
+
|
| 79 |
+
def __call__(self, text, default="eng"):
|
| 80 |
+
if text in self.cache:
|
| 81 |
+
return self.cache[text]
|
| 82 |
+
ids, langs = [], []
|
| 83 |
+
for l, s in segments(text, default):
|
| 84 |
+
t = self.t.encode(s)
|
| 85 |
+
ids += t; langs += [L2I[l]] * len(t)
|
| 86 |
+
self.cache[text] = (ids, langs)
|
| 87 |
+
return ids, langs
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
class FLM(nn.Module):
|
| 91 |
+
def __init__(self, q, n_spk, prefix, d=896):
|
| 92 |
+
super().__init__()
|
| 93 |
+
self.q = q
|
| 94 |
+
self.lang_emb = nn.Embedding(len(LANGS), d); nn.init.zeros_(self.lang_emb.weight)
|
| 95 |
+
self.spk_emb = nn.Embedding(n_spk, d); nn.init.normal_(self.spk_emb.weight, std=0.02)
|
| 96 |
+
self.rate_emb = nn.Embedding(len(RATES), d, padding_idx=0); nn.init.zeros_(self.rate_emb.weight)
|
| 97 |
+
self.adv = nn.Sequential(nn.Linear(d, 256), nn.ReLU(), nn.Linear(256, n_spk))
|
| 98 |
+
self.V = q.speech_token_size
|
| 99 |
+
self.EOS = q.eos_token
|
| 100 |
+
self.register_buffer("prefix", torch.tensor(prefix, dtype=torch.long), persistent=False)
|
| 101 |
+
|
| 102 |
+
def embed_text(self, ids, langs):
|
| 103 |
+
return self.q.llm.model.model.embed_tokens(ids) + self.lang_emb(langs)
|
| 104 |
+
|
| 105 |
+
def spkvec(self, spk):
|
| 106 |
+
return self.spk_emb(spk[0]) + self.rate_emb(spk[1])
|
| 107 |
+
|
| 108 |
+
def build(self, ids, langs, spk, sp=None, pids=None, plangs=None, psp=None):
|
| 109 |
+
E = self.q.speech_embedding.weight
|
| 110 |
+
if pids is not None:
|
| 111 |
+
ids = torch.cat([pids, ids]); langs = torch.cat([plangs, langs])
|
| 112 |
+
pre = self.q.llm.model.model.embed_tokens(self.prefix.to(ids.device))
|
| 113 |
+
parts = [E[self.q.sos][None], pre, self.embed_text(ids, langs), self.spkvec(spk)[None], E[self.q.task_id][None]]
|
| 114 |
+
npsp = 0
|
| 115 |
+
if psp is not None:
|
| 116 |
+
parts.append(self.q.speech_embedding(psp)); npsp = len(psp)
|
| 117 |
+
if sp is not None:
|
| 118 |
+
parts.append(self.q.speech_embedding(sp))
|
| 119 |
+
return torch.cat(parts, 0), len(pre), len(ids), npsp
|
| 120 |
+
|
| 121 |
+
def hidden(self, x, mask):
|
| 122 |
+
return self.q.llm.model.model(inputs_embeds=x, attention_mask=mask, return_dict=True).last_hidden_state
|
| 123 |
+
|
| 124 |
+
def pack(self, batch):
|
| 125 |
+
seqs, tgts, tpos, spks = [], [], [], []
|
| 126 |
+
for b in batch:
|
| 127 |
+
ids, langs, spk, sp = b[:4]
|
| 128 |
+
pr = b[4] if len(b) > 4 else None
|
| 129 |
+
x, P, nt, npsp = self.build(ids, langs, spk, sp, *(pr if pr else (None, None, None)))
|
| 130 |
+
tgt = torch.full((x.shape[0] + 1,), -100, device=x.device, dtype=torch.long)
|
| 131 |
+
start = P + nt + 2 + npsp
|
| 132 |
+
tgt[start: start + len(sp)] = sp
|
| 133 |
+
tgt[start + len(sp)] = self.EOS
|
| 134 |
+
seqs.append(x); tgts.append(tgt[:x.shape[0]]); tpos.append((1 + P, 1 + P + nt)); spks.append(int(spk[0]))
|
| 135 |
+
Tm = max(s.shape[0] for s in seqs); D = seqs[0].shape[1]
|
| 136 |
+
X = seqs[0].new_zeros(len(seqs), Tm, D)
|
| 137 |
+
Y = torch.full((len(seqs), Tm), -100, device=X.device, dtype=torch.long)
|
| 138 |
+
M = torch.zeros(len(seqs), Tm, device=X.device, dtype=torch.long)
|
| 139 |
+
for i, (s, t) in enumerate(zip(seqs, tgts)):
|
| 140 |
+
X[i, :len(s)] = s; Y[i, :len(t)] = t; M[i, :len(s)] = 1
|
| 141 |
+
return X, Y, M, tpos, spks
|
| 142 |
+
|
| 143 |
+
def forward2(self, batch, adv_lambda=1.0):
|
| 144 |
+
X, Y, M, tpos, spks = self.pack(batch)
|
| 145 |
+
H = self.hidden(X, M)
|
| 146 |
+
logits = self.q.llm_decoder(H)
|
| 147 |
+
ce = F.cross_entropy(logits.float().reshape(-1, logits.shape[-1]), Y.reshape(-1), ignore_index=-100)
|
| 148 |
+
valid = Y != -100
|
| 149 |
+
acc = (logits.argmax(-1)[valid] == Y[valid]).float().mean()
|
| 150 |
+
hs = torch.cat([H[i, a:b] for i, (a, b) in enumerate(tpos)])
|
| 151 |
+
ys = torch.cat([torch.full((b - a,), spks[i], device=X.device) for i, (a, b) in enumerate(tpos)])
|
| 152 |
+
al = self.adv(grad_reverse(hs.float(), adv_lambda))
|
| 153 |
+
return ce, acc, F.cross_entropy(al, ys), (al.argmax(-1) == ys).float().mean()
|
| 154 |
+
|
| 155 |
+
def seq_logp(self, batch):
|
| 156 |
+
"""sum log p(speech tokens + eos) per item (for DPO)."""
|
| 157 |
+
X, Y, M, _, _ = self.pack(batch)
|
| 158 |
+
logits = self.q.llm_decoder(self.hidden(X, M)).float()
|
| 159 |
+
lp = logits.log_softmax(-1)
|
| 160 |
+
valid = Y != -100
|
| 161 |
+
g = lp.gather(-1, Y.clamp(min=0)[..., None])[..., 0] * valid
|
| 162 |
+
return g.sum(-1), valid.sum(-1)
|
| 163 |
+
|
| 164 |
+
@torch.no_grad()
|
| 165 |
+
def generate(self, ids, langs, spk, prompt=None, B=1, top_p=0.8, top_k=25, win=10, tau_r=0.1, seed=0,
|
| 166 |
+
min_ratio=2.0, max_ratio=30.0, sampler="silexcap", max_tok=900):
|
| 167 |
+
g = torch.Generator(device=ids.device).manual_seed(seed)
|
| 168 |
+
x, _, _, _ = self.build(ids, langs, spk, None, *(prompt if prompt else (None, None, None)))
|
| 169 |
+
inp = x[None].repeat(B, 1, 1)
|
| 170 |
+
n = len(ids)
|
| 171 |
+
min_len, max_len = int(n * min_ratio), min(int(n * max_ratio), max_tok)
|
| 172 |
+
past, outs, done = None, [[] for _ in range(B)], [False] * B
|
| 173 |
+
E = self.q.speech_embedding.weight
|
| 174 |
+
for i in range(max_len):
|
| 175 |
+
o = self.q.llm.model.model(inputs_embeds=inp, past_key_values=past, use_cache=True, return_dict=True)
|
| 176 |
+
past = o.past_key_values
|
| 177 |
+
logp = self.q.llm_decoder(o.last_hidden_state[:, -1]).float().log_softmax(-1)
|
| 178 |
+
eos_lp = logp[:, self.EOS].clone()
|
| 179 |
+
logp[:, self.V:] = -float("inf")
|
| 180 |
+
if i >= min_len:
|
| 181 |
+
logp[:, self.EOS] = eos_lp
|
| 182 |
+
P = logp.exp()
|
| 183 |
+
nxt = []
|
| 184 |
+
for b in range(B):
|
| 185 |
+
if done[b]:
|
| 186 |
+
nxt.append(0); continue
|
| 187 |
+
p = P[b]; out = outs[b]
|
| 188 |
+
sp_, si = p.sort(descending=True)
|
| 189 |
+
keep = (sp_.cumsum(0) - sp_) < top_p
|
| 190 |
+
keep[top_k:] = False
|
| 191 |
+
cp, ci = sp_[keep], si[keep]
|
| 192 |
+
t = int(ci[torch.multinomial(cp / cp.sum(), 1, generator=g)])
|
| 193 |
+
exempt = False
|
| 194 |
+
if sampler == "silexcap" and t in SIL:
|
| 195 |
+
run = 0
|
| 196 |
+
for u in reversed(out):
|
| 197 |
+
if u not in SIL:
|
| 198 |
+
break
|
| 199 |
+
run += 1
|
| 200 |
+
exempt = run < 25
|
| 201 |
+
if not exempt and out and t != self.EOS and sum(1 for u in out[-win:] if u == t) >= win * tau_r:
|
| 202 |
+
t = int(torch.multinomial(p, 1, generator=g))
|
| 203 |
+
if t >= self.V:
|
| 204 |
+
done[b] = True; nxt.append(0); continue
|
| 205 |
+
out.append(t); nxt.append(t)
|
| 206 |
+
if all(done):
|
| 207 |
+
break
|
| 208 |
+
inp = E[torch.tensor(nxt, device=ids.device)][:, None]
|
| 209 |
+
return outs
|
| 210 |
+
|
| 211 |
+
|
| 212 |
+
def load_model(cosy, ckpt, tok):
|
| 213 |
+
ck = torch.load(ckpt, map_location="cuda", weights_only=False)
|
| 214 |
+
m = FLM(cosy.model.llm, ck["n_spk"], tok.prefix).cuda().eval()
|
| 215 |
+
print("load", ckpt, m.load_state_dict(ck["model"], strict=False), flush=True)
|
| 216 |
+
return m, json.load(open(os.path.join(os.path.dirname(ckpt), "spk2id.json")))
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
# ------------------------------------------------------------------ data
|
| 220 |
+
def load_data(splits, max_tok=750, extra_man=None, qual=None, qual_drop=0.1):
|
| 221 |
+
rows = [json.loads(l) for l in open(MAN, encoding="utf-8")]
|
| 222 |
+
if extra_man and os.path.exists(extra_man):
|
| 223 |
+
rows += [json.loads(l) for l in open(extra_man, encoding="utf-8")]
|
| 224 |
+
want = {r["id"] for r in rows if r["split"] in splits}
|
| 225 |
+
drop = set()
|
| 226 |
+
if qual and os.path.exists(qual) and "train" in splits: # drop the bottom qual_drop of UTMOS per source
|
| 227 |
+
Q = [json.loads(l) for l in open(qual)]
|
| 228 |
+
by = {}
|
| 229 |
+
for q in Q:
|
| 230 |
+
by.setdefault(q["src"], []).append(q)
|
| 231 |
+
for src, L in by.items():
|
| 232 |
+
if src in ("cs_pairs",):
|
| 233 |
+
continue
|
| 234 |
+
thr = float(np.quantile([q["u22"] for q in L], qual_drop))
|
| 235 |
+
drop |= {q["id"] for q in L if q["u22"] < thr}
|
| 236 |
+
print("quality filter drops", len(drop), flush=True)
|
| 237 |
+
src_idx, mm = {}, {}
|
| 238 |
+
for src in sorted({r["src"] for r in rows}):
|
| 239 |
+
if src in NEW:
|
| 240 |
+
d = f"{HOME}/p3t/{src}"
|
| 241 |
+
elif src == "igbosyn_pseudo":
|
| 242 |
+
d = f"{HOME}/flash/data/igbosyn_pseudo"
|
| 243 |
+
else:
|
| 244 |
+
d = f"{HOME}/data3/{src}"
|
| 245 |
+
if not os.path.exists(f"{d}/s3v3.done"):
|
| 246 |
+
print("missing v3 tokens", d, flush=True); continue
|
| 247 |
+
meta = [json.loads(l) for l in open(f"{d}/meta.jsonl", encoding="utf-8")]
|
| 248 |
+
tk = [json.loads(l) for l in open(f"{d}/s3v3.jsonl")]
|
| 249 |
+
ix = {}
|
| 250 |
+
for k, (m, t) in enumerate(zip(meta, tk)):
|
| 251 |
+
assert m["id"] == t["id"]
|
| 252 |
+
if m["id"] in want:
|
| 253 |
+
ix[m["id"]] = (t["toff"], t["ntok"])
|
| 254 |
+
src_idx[src] = ix
|
| 255 |
+
mm[src] = np.memmap(f"{d}/s3v3.i32", dtype=np.int32, mode="r")
|
| 256 |
+
items = []
|
| 257 |
+
for r in rows:
|
| 258 |
+
if r["split"] not in splits or r["src"] not in src_idx or r["id"] in drop and r["speaker"] != ANCHOR:
|
| 259 |
+
continue
|
| 260 |
+
ix = src_idx[r["src"]]
|
| 261 |
+
if r["id"] not in ix:
|
| 262 |
+
continue
|
| 263 |
+
toff, ntok = ix[r["id"]]
|
| 264 |
+
if not (5 < ntok <= max_tok):
|
| 265 |
+
continue
|
| 266 |
+
w = float(r.get("weight", 1.0)) * FLASH_W.get(r["src"], 1.0)
|
| 267 |
+
items.append(dict(id=r["id"], ds=r["src"], src=r["src"], lang=r["lang"], spk=r["speaker"], split=r["split"],
|
| 268 |
+
dur=r["dur"], text=r["text_plain"], tags=r.get("text_tags"), rate=R2I.get(r.get("rate_bin"), 0),
|
| 269 |
+
w=w, toff=toff, ntok=ntok))
|
| 270 |
+
return items, mm
|
| 271 |
+
|
| 272 |
+
|
| 273 |
+
def tagged(text, lang):
|
| 274 |
+
return text if lang == "cs" else f"<{lang}>{text}</{lang}>"
|
| 275 |
+
|
| 276 |
+
|
| 277 |
+
def batches(items, budget, rng, wfn, cost):
|
| 278 |
+
idx = []
|
| 279 |
+
for i, m in enumerate(items):
|
| 280 |
+
w = wfn(m)
|
| 281 |
+
idx += [i] * int(w) + ([i] if rng.random() < w - int(w) else [])
|
| 282 |
+
idx.sort(key=lambda i: cost(items[i]) + rng.random() * 10)
|
| 283 |
+
out, cur, mx = [], [], 0
|
| 284 |
+
for i in idx:
|
| 285 |
+
L = cost(items[i])
|
| 286 |
+
if cur and max(mx, L) * (len(cur) + 1) > budget:
|
| 287 |
+
out.append(cur); cur, mx = [], 0
|
| 288 |
+
cur.append(i); mx = max(mx, L)
|
| 289 |
+
if cur:
|
| 290 |
+
out.append(cur)
|
| 291 |
+
rng.shuffle(out)
|
| 292 |
+
return out
|
| 293 |
+
|
| 294 |
+
|
| 295 |
+
VAL_SPLITS = {"val", "validation", "dev"}
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
def train_lm(a):
|
| 299 |
+
cosy = load_cv3(); tok = Tok(cosy)
|
| 300 |
+
items, mm = load_data({"train"}, a.max_tok, a.extra_man, a.qual, a.qual_drop)
|
| 301 |
+
val_all, mmv = load_data(VAL_SPLITS, a.max_tok)
|
| 302 |
+
mm.update(mmv)
|
| 303 |
+
spk2id = {}
|
| 304 |
+
for s in sorted({m["spk"] for m in items}):
|
| 305 |
+
spk2id[s] = len(spk2id)
|
| 306 |
+
n_spk = len(spk2id)
|
| 307 |
+
rng = random.Random(1); rng.shuffle(val_all)
|
| 308 |
+
val, per_l, per_s = [], {}, {}
|
| 309 |
+
for m in val_all:
|
| 310 |
+
if m["spk"] not in spk2id or m["lang"] == "cs":
|
| 311 |
+
continue
|
| 312 |
+
L = "anchor" if m["spk"] == ANCHOR else m["lang"]
|
| 313 |
+
if per_l.get(L, 0) >= 60 or per_s.get(m["spk"], 0) >= 15:
|
| 314 |
+
continue
|
| 315 |
+
per_l[L] = per_l.get(L, 0) + 1; per_s[m["spk"]] = per_s.get(m["spk"], 0) + 1; val.append(m)
|
| 316 |
+
by_spk = {}
|
| 317 |
+
for m in items:
|
| 318 |
+
if m["ntok"] <= 200 and m["lang"] != "cs":
|
| 319 |
+
by_spk.setdefault(m["spk"], []).append(m)
|
| 320 |
+
os.makedirs(a.out, exist_ok=True)
|
| 321 |
+
json.dump(spk2id, open(f"{a.out}/spk2id.json", "w")); json.dump(vars(a), open(f"{a.out}/args.json", "w"))
|
| 322 |
+
hrs = {}
|
| 323 |
+
for m in items:
|
| 324 |
+
hrs[m["src"]] = hrs.get(m["src"], 0) + m["dur"] / 3600
|
| 325 |
+
print("lm items", len(items), "hours", round(sum(hrs.values()), 1), {k: round(v, 1) for k, v in hrs.items()},
|
| 326 |
+
"spk", n_spk, "val", len(val), per_l, flush=True)
|
| 327 |
+
model = FLM(cosy.model.llm, n_spk, tok.prefix).cuda().train()
|
| 328 |
+
for p in list(cosy.model.flow.parameters()) + list(cosy.model.hift.parameters()):
|
| 329 |
+
p.requires_grad = False
|
| 330 |
+
new = list(model.lang_emb.parameters()) + list(model.spk_emb.parameters()) + list(model.adv.parameters()) + list(model.rate_emb.parameters())
|
| 331 |
+
newids = {id(p) for p in new}
|
| 332 |
+
old = [p for p in model.parameters() if id(p) not in newids and p.requires_grad]
|
| 333 |
+
opt = torch.optim.AdamW([{"params": old, "lr": a.lr}, {"params": new, "lr": a.lr_new}], weight_decay=0.01)
|
| 334 |
+
base = [a.lr, a.lr_new]
|
| 335 |
+
|
| 336 |
+
def text_of(m, r):
|
| 337 |
+
if m["tags"] and r is not None and r.random() >= a.tag_drop:
|
| 338 |
+
return m["tags"]
|
| 339 |
+
return strip_tags(m["text"])
|
| 340 |
+
|
| 341 |
+
def spk_t(m, r):
|
| 342 |
+
rate = m["rate"] if (r is not None and r.random() >= a.rate_drop) else 0
|
| 343 |
+
return torch.tensor([spk2id[m["spk"]], rate]).cuda()
|
| 344 |
+
|
| 345 |
+
def enc(m, prng=None, force_prompt=None, val_mode=False):
|
| 346 |
+
r = None if val_mode else prng
|
| 347 |
+
ids, langs = tok(tagged(text_of(m, r), m["lang"]))
|
| 348 |
+
sp = np.asarray(mm[m["ds"]][m["toff"]: m["toff"] + m["ntok"]], dtype=np.int64)
|
| 349 |
+
out = [torch.tensor(ids).cuda(), torch.tensor(langs).cuda(), spk_t(m, r), torch.from_numpy(sp).cuda()]
|
| 350 |
+
use = force_prompt if force_prompt is not None else (prng is not None and prng.random() < a.p_prompt)
|
| 351 |
+
if use:
|
| 352 |
+
c = by_spk.get(m["spk"], [])
|
| 353 |
+
c = [x for x in (prng or random).sample(c, min(6, len(c))) if x["id"] != m["id"]] if c else []
|
| 354 |
+
if c and c[0]["ntok"] + m["ntok"] <= a.max_tok + 150:
|
| 355 |
+
p = c[0]
|
| 356 |
+
pids, plangs = tok(tagged(strip_tags(p["text"]), p["lang"]))
|
| 357 |
+
psp = np.asarray(mm[p["ds"]][p["toff"]: p["toff"] + p["ntok"]], dtype=np.int64)
|
| 358 |
+
out.append((torch.tensor(pids).cuda(), torch.tensor(plangs).cuda(), torch.from_numpy(psp).cuda()))
|
| 359 |
+
return out
|
| 360 |
+
|
| 361 |
+
def validate():
|
| 362 |
+
model.eval(); res = {}
|
| 363 |
+
with torch.no_grad(), torch.autocast("cuda", dtype=torch.bfloat16):
|
| 364 |
+
for mode in (False, True):
|
| 365 |
+
vr = random.Random(7); L, W = [], []
|
| 366 |
+
for i in range(0, len(val), 16):
|
| 367 |
+
bt = val[i:i + 16]
|
| 368 |
+
ce, _, _, _ = model.forward2([enc(m, vr, force_prompt=mode, val_mode=True) for m in bt])
|
| 369 |
+
L.append(float(ce) * len(bt)); W.append(len(bt))
|
| 370 |
+
res["p" if mode else "np"] = sum(L) / sum(W)
|
| 371 |
+
model.train()
|
| 372 |
+
res["mean"] = (res["np"] + res["p"]) / 2
|
| 373 |
+
return res
|
| 374 |
+
|
| 375 |
+
wfn = lambda m: m["w"] * (a.anchor_w if m["spk"] == ANCHOR else 1.0) # noqa
|
| 376 |
+
cost = lambda m: (lambda L: int(L * (1 + L / a.quad)))(m["ntok"] + len(m["text"]) // 2 + 20 + int(a.p_prompt * 200)) # noqa
|
| 377 |
+
rng = random.Random(0); prng = random.Random(3)
|
| 378 |
+
step, nskip, noom, t0 = 0, 0, 0, time.time()
|
| 379 |
+
logf = open(f"{a.out}/log.jsonl", "a")
|
| 380 |
+
v = validate(); best = v["mean"]; bad = 0
|
| 381 |
+
print(json.dumps({"step": 0, "val": v}), flush=True); logf.write(json.dumps({"step": 0, "val": v}) + "\n")
|
| 382 |
+
total, done = a.max_steps, False
|
| 383 |
+
while not done:
|
| 384 |
+
for bi in batches(items, a.tokens, rng, wfn, cost):
|
| 385 |
+
lrm = min(1.0, (step + 1) / a.warmup) * (0.1 + 0.9 * 0.5 * (1 + math.cos(math.pi * min(1.0, step / total))))
|
| 386 |
+
for gp, b in zip(opt.param_groups, base):
|
| 387 |
+
gp["lr"] = b * lrm
|
| 388 |
+
batch = [enc(items[i], prng) for i in bi]
|
| 389 |
+
opt.zero_grad(set_to_none=True)
|
| 390 |
+
oom = False
|
| 391 |
+
try:
|
| 392 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 393 |
+
ce, acc, adv, adv_acc = model.forward2(batch, adv_lambda=min(1.0, step / 1000))
|
| 394 |
+
loss = ce + a.adv_w * adv
|
| 395 |
+
if not torch.isfinite(loss):
|
| 396 |
+
nskip += 1; continue
|
| 397 |
+
loss.backward()
|
| 398 |
+
except torch.cuda.OutOfMemoryError:
|
| 399 |
+
oom = True
|
| 400 |
+
if oom:
|
| 401 |
+
batch = ce = acc = adv = adv_acc = loss = None
|
| 402 |
+
opt.zero_grad(set_to_none=True); torch.cuda.empty_cache(); noom += 1; continue
|
| 403 |
+
gn = torch.nn.utils.clip_grad_norm_([p for p in model.parameters() if p.requires_grad], 1.0)
|
| 404 |
+
if not torch.isfinite(gn):
|
| 405 |
+
nskip += 1; opt.zero_grad(set_to_none=True); continue
|
| 406 |
+
opt.step(); step += 1
|
| 407 |
+
if step % 50 == 0:
|
| 408 |
+
r = dict(step=step, ce=round(float(ce), 4), acc=round(float(acc), 4), adv=round(float(adv), 3),
|
| 409 |
+
adv_acc=round(float(adv_acc), 3), gn=round(float(gn), 2), B=len(bi), lr=round(lrm * a.lr, 9),
|
| 410 |
+
skips=nskip, oom=noom, min=round((time.time() - t0) / 60, 2))
|
| 411 |
+
print(json.dumps(r), flush=True); logf.write(json.dumps(r) + "\n"); logf.flush()
|
| 412 |
+
if step % a.val_every == 0:
|
| 413 |
+
v = validate(); imp = v["mean"] < best - 1e-4
|
| 414 |
+
rec = {"step": step, "val": v, "best": imp}
|
| 415 |
+
print(json.dumps(rec), flush=True); logf.write(json.dumps(rec) + "\n"); logf.flush()
|
| 416 |
+
if imp:
|
| 417 |
+
best, bad = v["mean"], 0
|
| 418 |
+
torch.save(dict(model={k: t for k, t in model.state_dict().items()}, step=step, n_spk=n_spk, val=v), f"{a.out}/best.pt")
|
| 419 |
+
else:
|
| 420 |
+
bad += 1
|
| 421 |
+
if bad >= a.patience:
|
| 422 |
+
print("EARLY_STOP", step, flush=True); done = True; break
|
| 423 |
+
if (time.time() - t0) / 60 > a.minutes or step >= total:
|
| 424 |
+
done = True; break
|
| 425 |
+
print("TRAIN_LM_DONE", step, "best", best, "skips", nskip, "oom", noom, flush=True)
|
| 426 |
+
|
| 427 |
+
|
| 428 |
+
# ------------------------------------------------------------------ synthesis
|
| 429 |
+
def prompt_feats(cosy, wav):
|
| 430 |
+
fe = cosy.frontend
|
| 431 |
+
tokn, _ = fe._extract_speech_token(wav)
|
| 432 |
+
feat, _ = fe._extract_speech_feat(wav)
|
| 433 |
+
n = min(feat.shape[1] // 2, tokn.shape[1])
|
| 434 |
+
return tokn[:, :n].cuda(), feat[:, :2 * n].cuda(), fe._extract_spk_embedding(wav).cuda()
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
@torch.no_grad()
|
| 438 |
+
def token2wav(cosy, tokens, ptok, pfeat, emb):
|
| 439 |
+
flow = cosy.model.flow
|
| 440 |
+
t = torch.tensor([tokens], dtype=torch.int32).cuda()
|
| 441 |
+
mel, _ = flow.inference(token=t, token_len=torch.tensor([t.shape[1]], dtype=torch.int32).cuda(),
|
| 442 |
+
prompt_token=ptok.int(), prompt_token_len=torch.tensor([ptok.shape[1]], dtype=torch.int32).cuda(),
|
| 443 |
+
prompt_feat=pfeat, prompt_feat_len=torch.tensor([pfeat.shape[1]], dtype=torch.int32).cuda(),
|
| 444 |
+
embedding=emb, streaming=False, finalize=True)
|
| 445 |
+
w, _ = cosy.model.hift.inference(speech_feat=mel, finalize=True)
|
| 446 |
+
return w.squeeze().float().cpu().numpy()
|
| 447 |
+
|
| 448 |
+
|
| 449 |
+
def item_text(r):
|
| 450 |
+
return r["text"] if r["lang"] in ("cs", "para") else f"<{r['lang']}>{r['text']}</{r['lang']}>"
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
class Synth:
|
| 454 |
+
def __init__(self, lm_ckpt):
|
| 455 |
+
self.cosy = load_cv3(); self.tok = Tok(self.cosy)
|
| 456 |
+
self.m, self.spk2id = load_model(self.cosy, lm_ckpt, self.tok)
|
| 457 |
+
self.vcache = {}
|
| 458 |
+
vt = f"{PDIR}/flash_voices_text.json"
|
| 459 |
+
self.vtext = json.load(open(vt if os.path.exists(vt) else f"{_HERE}/voices_text.json", encoding="utf-8"))
|
| 460 |
+
|
| 461 |
+
def voice(self, name):
|
| 462 |
+
if name not in self.vcache:
|
| 463 |
+
v = VOICES[name]
|
| 464 |
+
ptok, pfeat, emb = prompt_feats(self.cosy, v["wav"])
|
| 465 |
+
ids, langs = self.tok(self.vtext[name])
|
| 466 |
+
lmp = (torch.tensor(ids).cuda(), torch.tensor(langs).cuda(), ptok[0].long())
|
| 467 |
+
self.vcache[name] = (ptok, pfeat, emb, lmp, self.spk2id.get(v["spk"], self.spk2id.get(ANCHOR)))
|
| 468 |
+
return self.vcache[name]
|
| 469 |
+
|
| 470 |
+
def tokens(self, text, voice="anchor", rate="normal", seed=0, B=1, sampler="silexcap"):
|
| 471 |
+
ptok, pfeat, emb, lmp, sid = self.voice(voice)
|
| 472 |
+
ids, langs = self.tok(text)
|
| 473 |
+
spk = torch.tensor([sid, R2I.get(None if rate == "none" else rate, 0)]).cuda()
|
| 474 |
+
with torch.autocast("cuda", dtype=torch.bfloat16):
|
| 475 |
+
return self.m.generate(torch.tensor(ids).cuda(), torch.tensor(langs).cuda(), spk, prompt=lmp, B=B, seed=seed,
|
| 476 |
+
sampler=sampler)
|
| 477 |
+
|
| 478 |
+
def wav(self, toks, voice="anchor"):
|
| 479 |
+
ptok, pfeat, emb, _, _ = self.voice(voice)
|
| 480 |
+
if len(toks) < 3:
|
| 481 |
+
toks = list(toks) + [1, 1, 1]
|
| 482 |
+
return token2wav(self.cosy, toks, ptok, pfeat, emb)
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
def gen(a):
|
| 486 |
+
S = Synth(a.lm)
|
| 487 |
+
rows = [json.loads(l) for l in open(a.rows, encoding="utf-8")]
|
| 488 |
+
if a.shard:
|
| 489 |
+
i, n = map(int, a.shard.split("/")); rows = rows[i::n]
|
| 490 |
+
os.makedirs(a.out, exist_ok=True)
|
| 491 |
+
json.dump(vars(a), open(f"{a.out}/variant.json", "w"))
|
| 492 |
+
for r in rows:
|
| 493 |
+
if os.path.exists(f"{a.out}/{r['id']}.wav"):
|
| 494 |
+
continue
|
| 495 |
+
text = r.get("tts_text") or item_text(r)
|
| 496 |
+
toks = S.tokens(text, a.voice, a.rate, a.seed)[0]
|
| 497 |
+
w = S.wav(toks, a.voice)
|
| 498 |
+
sf.write(f"{a.out}/{r['id']}.wav", w, S.cosy.sample_rate)
|
| 499 |
+
json.dump(dict(tokens=[toks], ntok=[len(toks)]), open(f"{a.out}/{r['id']}.tok.json", "w"))
|
| 500 |
+
print("GEN_DONE", a.out, len(rows), flush=True)
|
| 501 |
+
|
| 502 |
+
|
| 503 |
+
if __name__ == "__main__":
|
| 504 |
+
ap = argparse.ArgumentParser()
|
| 505 |
+
ap.add_argument("cmd")
|
| 506 |
+
ap.add_argument("--out", required=True)
|
| 507 |
+
ap.add_argument("--lm")
|
| 508 |
+
ap.add_argument("--rows", default=f"{HOME}/flash/score/rows_flash.jsonl")
|
| 509 |
+
ap.add_argument("--voice", default="anchor")
|
| 510 |
+
ap.add_argument("--rate", default="normal")
|
| 511 |
+
ap.add_argument("--seed", type=int, default=0)
|
| 512 |
+
ap.add_argument("--shard")
|
| 513 |
+
ap.add_argument("--minutes", type=float, default=75)
|
| 514 |
+
ap.add_argument("--max_steps", type=int, default=12000)
|
| 515 |
+
ap.add_argument("--lr", type=float, default=2e-5)
|
| 516 |
+
ap.add_argument("--lr_new", type=float, default=1e-3)
|
| 517 |
+
ap.add_argument("--warmup", type=int, default=300)
|
| 518 |
+
ap.add_argument("--tokens", type=int, default=16000)
|
| 519 |
+
ap.add_argument("--max_tok", type=int, default=750)
|
| 520 |
+
ap.add_argument("--adv_w", type=float, default=0.02)
|
| 521 |
+
ap.add_argument("--p_prompt", type=float, default=0.5)
|
| 522 |
+
ap.add_argument("--tag_drop", type=float, default=0.5)
|
| 523 |
+
ap.add_argument("--rate_drop", type=float, default=0.5)
|
| 524 |
+
ap.add_argument("--anchor_w", type=float, default=1.0)
|
| 525 |
+
ap.add_argument("--val_every", type=int, default=1000)
|
| 526 |
+
ap.add_argument("--patience", type=int, default=4)
|
| 527 |
+
ap.add_argument("--quad", type=float, default=600.0)
|
| 528 |
+
ap.add_argument("--extra_man", default=f"{HOME}/flash/data/igbosyn_pseudo/manifest.jsonl")
|
| 529 |
+
ap.add_argument("--qual", default=f"{HOME}/flash/qual/utmos_train.jsonl")
|
| 530 |
+
ap.add_argument("--qual_drop", type=float, default=0.1)
|
| 531 |
+
a = ap.parse_args()
|
| 532 |
+
{"lm": train_lm, "gen": gen}[a.cmd](a)
|
frontend/__init__.py
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dynamic Accent Flash text front-end (normalisation, Yoruba/Igbo diacritic restoration, experimental MT)."""
|
| 2 |
+
from .frontend import FrontEnd # noqa: F401
|
frontend/frontend.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dynamic Accent Flash text front-end.
|
| 2 |
+
|
| 3 |
+
from frontend import FrontEnd
|
| 4 |
+
fe = FrontEnd(diac_model="models/diacritics", mt=True)
|
| 5 |
+
fe("<eng>The meeting is at 3:30 on 21/10/2026.</eng>", mode="codeswitch") # tags kept, numbers verbalised
|
| 6 |
+
fe("Ojo naa dara pupo", mode="native", lang="yor") # adds Yorùbá tone marks/underdots
|
| 7 |
+
fe("Please come home early today.", mode="translate", lang="ibo") # MADLAD-400 eng/pcm -> ibo
|
| 8 |
+
fe("I go call you tomorrow", mode="accent", lang="ibo") # English/Pidgin words, Igbo accent
|
| 9 |
+
|
| 10 |
+
Modes
|
| 11 |
+
codeswitch : input already tagged <ibo>…</ibo> <eng>…</eng> (or untagged = one language `lang`); each segment is
|
| 12 |
+
normalised in its own language; Yorùbá/Igbo segments that carry no marks are diacritised.
|
| 13 |
+
native : the whole text is one language (`lang`); normalise + diacritise.
|
| 14 |
+
translate : `lang` is the target (ibo|yor|hau); the input (English or Pidgin) is translated first with
|
| 15 |
+
MADLAD-400-3B-MT (Apache-2.0), then normalised + diacritised (MADLAD Yorùbá is often unmarked).
|
| 16 |
+
accent : keep the words as written but read them with the `lang` accent (whole text tagged <lang>), i.e.
|
| 17 |
+
"English words with a native accent". Numbers are verbalised in English.
|
| 18 |
+
Output: a tagged string for infer.py / flash_lm.py.
|
| 19 |
+
"""
|
| 20 |
+
import re
|
| 21 |
+
import unicodedata
|
| 22 |
+
|
| 23 |
+
try:
|
| 24 |
+
from .normalize import normalize
|
| 25 |
+
except ImportError: # run as a script
|
| 26 |
+
from normalize import normalize
|
| 27 |
+
|
| 28 |
+
SEG = re.compile(r"<(\w{3})>(.*?)</\1>", re.S)
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
def _strip(s):
|
| 32 |
+
return "".join(c for c in unicodedata.normalize("NFD", s) if unicodedata.category(c) != "Mn")
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def unmarked(text, thresh=0.05):
|
| 36 |
+
w = re.findall(r"\w+", unicodedata.normalize("NFC", text))
|
| 37 |
+
if not w:
|
| 38 |
+
return False
|
| 39 |
+
return sum(_strip(x) != unicodedata.normalize("NFC", x) for x in w) / len(w) < thresh
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
class FrontEnd:
|
| 43 |
+
def __init__(self, diac_model=None, mt=False, device="cuda"):
|
| 44 |
+
self.diac_dir, self.device = diac_model, device
|
| 45 |
+
self._d = self._mt = None
|
| 46 |
+
self.use_mt = mt
|
| 47 |
+
|
| 48 |
+
# ---- diacritics (ByT5-small fine-tune, word-guarded)
|
| 49 |
+
def diacritise(self, text, lang):
|
| 50 |
+
if lang not in ("yor", "ibo") or not self.diac_dir:
|
| 51 |
+
return text
|
| 52 |
+
import torch
|
| 53 |
+
from transformers import AutoTokenizer, T5ForConditionalGeneration
|
| 54 |
+
if self._d is None:
|
| 55 |
+
self._d = (AutoTokenizer.from_pretrained(self.diac_dir),
|
| 56 |
+
T5ForConditionalGeneration.from_pretrained(self.diac_dir).to(self.device).eval())
|
| 57 |
+
tok, m = self._d
|
| 58 |
+
src = unicodedata.normalize("NFC", _strip(text))
|
| 59 |
+
x = tok([f"{lang}: {src}"], return_tensors="pt").to(self.device)
|
| 60 |
+
with torch.no_grad():
|
| 61 |
+
y = m.generate(**x, max_length=int(x.input_ids.shape[1] * 1.6) + 16)
|
| 62 |
+
hyp = unicodedata.normalize("NFC", tok.decode(y[0], skip_special_tokens=True))
|
| 63 |
+
sw, hw = src.split(), hyp.split()
|
| 64 |
+
if len(sw) != len(hw):
|
| 65 |
+
return text
|
| 66 |
+
return " ".join(h if unicodedata.normalize("NFC", _strip(h)) == s else s for s, h in zip(sw, hw))
|
| 67 |
+
|
| 68 |
+
# ---- MT (MADLAD-400-3B-MT)
|
| 69 |
+
def translate(self, text, tgt):
|
| 70 |
+
import torch
|
| 71 |
+
from transformers import T5ForConditionalGeneration, T5Tokenizer
|
| 72 |
+
if self._mt is None:
|
| 73 |
+
self._mt = (T5Tokenizer.from_pretrained("google/madlad400-3b-mt"),
|
| 74 |
+
T5ForConditionalGeneration.from_pretrained("google/madlad400-3b-mt", torch_dtype=torch.bfloat16).to(self.device).eval())
|
| 75 |
+
tok, m = self._mt
|
| 76 |
+
code = {"ibo": "ig", "yor": "yo", "hau": "ha", "eng": "en"}[tgt]
|
| 77 |
+
out = []
|
| 78 |
+
for sent in re.split(r"(?<=[.!?])\s+", text.strip()):
|
| 79 |
+
if not sent:
|
| 80 |
+
continue
|
| 81 |
+
x = tok([f"<2{code}> {sent}"], return_tensors="pt").to(self.device)
|
| 82 |
+
with torch.no_grad():
|
| 83 |
+
y = m.generate(**x, max_new_tokens=256, num_beams=4)
|
| 84 |
+
out.append(tok.decode(y[0], skip_special_tokens=True))
|
| 85 |
+
return " ".join(out)
|
| 86 |
+
|
| 87 |
+
def _seg(self, lang, s):
|
| 88 |
+
s = normalize(s, lang)
|
| 89 |
+
if lang in ("yor", "ibo") and unmarked(s):
|
| 90 |
+
s = self.diacritise(s, lang)
|
| 91 |
+
return f"<{lang}>{s}</{lang}>"
|
| 92 |
+
|
| 93 |
+
def __call__(self, text, mode="codeswitch", lang="eng"):
|
| 94 |
+
text = unicodedata.normalize("NFC", text).strip()
|
| 95 |
+
if mode == "translate":
|
| 96 |
+
if lang not in ("ibo", "yor", "hau"):
|
| 97 |
+
raise ValueError("translate mode needs lang in ibo|yor|hau")
|
| 98 |
+
plain = re.sub(r"</?\w{3}>", "", text)
|
| 99 |
+
return self._seg(lang, self.translate(normalize(plain, "eng"), lang))
|
| 100 |
+
if mode == "accent":
|
| 101 |
+
plain = re.sub(r"</?\w{3}>", "", text)
|
| 102 |
+
return f"<{lang}>{normalize(plain, 'eng')}</{lang}>"
|
| 103 |
+
if mode == "native" or not SEG.search(text):
|
| 104 |
+
return self._seg(lang, re.sub(r"</?\w{3}>", "", text))
|
| 105 |
+
parts, pos = [], 0
|
| 106 |
+
for m in SEG.finditer(text):
|
| 107 |
+
if text[pos:m.start()].strip():
|
| 108 |
+
parts.append(self._seg(lang, text[pos:m.start()]))
|
| 109 |
+
parts.append(self._seg(m.group(1), m.group(2)))
|
| 110 |
+
pos = m.end()
|
| 111 |
+
if text[pos:].strip():
|
| 112 |
+
parts.append(self._seg(lang, text[pos:]))
|
| 113 |
+
return " ".join(parts)
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
if __name__ == "__main__":
|
| 117 |
+
import argparse
|
| 118 |
+
ap = argparse.ArgumentParser()
|
| 119 |
+
ap.add_argument("text"); ap.add_argument("--mode", default="codeswitch"); ap.add_argument("--lang", default="eng")
|
| 120 |
+
ap.add_argument("--diac_model", default=None); ap.add_argument("--cpu", action="store_true")
|
| 121 |
+
a = ap.parse_args()
|
| 122 |
+
print(FrontEnd(a.diac_model, device="cpu" if a.cpu else "cuda")(a.text, a.mode, a.lang))
|
frontend/normalize.py
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Dynamic Accent Flash text normaliser: numbers, ordinals-as-cardinals, years, dates, times, currency and percent
|
| 2 |
+
-> words, per language (eng, pcm, ibo, hau, yor). Pure Python, no dependencies.
|
| 3 |
+
|
| 4 |
+
from normalize import normalize
|
| 5 |
+
normalize("Ọ bụ ₦5,000 n'ụbọchị 21/10/2026", "ibo")
|
| 6 |
+
|
| 7 |
+
Coverage: integers 0 .. 999,999,999 (larger stay as digits), decimals (point-by-digit), ₦/N/NGN/naira, $/USD,
|
| 8 |
+
£, kobo, %, dd/mm/yyyy and "21 October 2026" dates, hh:mm times, 1st/2nd... in eng/pcm.
|
| 9 |
+
The Igbo and Hausa systems are decimal and regular. Yorùbá uses the traditional vigesimal/subtractive system for
|
| 10 |
+
1-99 (with tone marks) and decimal composition above 100 (ọgọ́rùn-ún, ẹgbẹ̀rún, mílíọ̀nù + "ó lé"); the Yorùbá forms and
|
| 11 |
+
all date/currency phrasings need a native-speaker check before release (see TEXT_FRONTEND.md).
|
| 12 |
+
"""
|
| 13 |
+
import re
|
| 14 |
+
import unicodedata
|
| 15 |
+
|
| 16 |
+
# ------------------------------------------------------------------ English / Pidgin
|
| 17 |
+
_E1 = "zero one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen".split()
|
| 18 |
+
_E10 = "_ _ twenty thirty forty fifty sixty seventy eighty ninety".split()
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
def eng(n):
|
| 22 |
+
if n < 20:
|
| 23 |
+
return _E1[n]
|
| 24 |
+
if n < 100:
|
| 25 |
+
return _E10[n // 10] + ("" if n % 10 == 0 else "-" + _E1[n % 10])
|
| 26 |
+
if n < 1000:
|
| 27 |
+
return _E1[n // 100] + " hundred" + ("" if n % 100 == 0 else " and " + eng(n % 100))
|
| 28 |
+
for v, w in ((10 ** 9, "billion"), (10 ** 6, "million"), (1000, "thousand")):
|
| 29 |
+
if n >= v:
|
| 30 |
+
r = n % v
|
| 31 |
+
tail = "" if r == 0 else ((" and " if r < 100 else " ") + eng(r))
|
| 32 |
+
return eng(n // v) + " " + w + tail
|
| 33 |
+
return str(n)
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def eng_year(n):
|
| 37 |
+
if 2000 <= n <= 2009:
|
| 38 |
+
return eng(n)
|
| 39 |
+
if 1100 <= n <= 2099 and n % 100 != 0:
|
| 40 |
+
return eng(n // 100) + " " + (("oh " + _E1[n % 100]) if n % 100 < 10 else eng(n % 100))
|
| 41 |
+
return eng(n)
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
_ORD = {"one": "first", "two": "second", "three": "third", "five": "fifth", "eight": "eighth", "nine": "ninth", "twelve": "twelfth"}
|
| 45 |
+
|
| 46 |
+
|
| 47 |
+
def eng_ord(n):
|
| 48 |
+
w = eng(n)
|
| 49 |
+
head, _, last = w.rpartition(" ") if " " in w else ("", "", w)
|
| 50 |
+
h2, dash, l2 = last.rpartition("-")
|
| 51 |
+
base = l2 if dash else last
|
| 52 |
+
o = _ORD.get(base) or (base[:-1] + "ieth" if base.endswith("y") else base + "th")
|
| 53 |
+
last = (h2 + "-" + o) if dash else o
|
| 54 |
+
return (head + " " + last).strip()
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# ------------------------------------------------------------------ Igbo (decimal)
|
| 58 |
+
_I1 = ["efu", "otu", "abụọ", "atọ", "anọ", "ise", "isii", "asaa", "asatọ", "itoolu"]
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
def ibo(n):
|
| 62 |
+
if n < 10:
|
| 63 |
+
return _I1[n]
|
| 64 |
+
if n < 100:
|
| 65 |
+
t, u = divmod(n, 10)
|
| 66 |
+
s = "iri" if t == 1 else "iri " + _I1[t]
|
| 67 |
+
return s if u == 0 else s + " na " + _I1[u]
|
| 68 |
+
for v, w in ((10 ** 9, "ijeri"), (10 ** 6, "nde"), (1000, "puku"), (100, "narị")):
|
| 69 |
+
if n >= v:
|
| 70 |
+
q, r = divmod(n, v)
|
| 71 |
+
s = w if q == 1 else w + " " + ibo(q)
|
| 72 |
+
return s if r == 0 else s + " na " + ibo(r)
|
| 73 |
+
return str(n)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
# ------------------------------------------------------------------ Hausa (decimal)
|
| 77 |
+
_H1 = ["sifili", "ɗaya", "biyu", "uku", "huɗu", "biyar", "shida", "bakwai", "takwas", "tara"]
|
| 78 |
+
_H10 = [None, "goma", "ashirin", "talatin", "arba'in", "hamsin", "sittin", "saba'in", "tamanin", "casa'in"]
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def hau(n):
|
| 82 |
+
if n < 10:
|
| 83 |
+
return _H1[n]
|
| 84 |
+
if n < 20:
|
| 85 |
+
return "goma" if n == 10 else "goma sha " + _H1[n - 10]
|
| 86 |
+
if n < 100:
|
| 87 |
+
t, u = divmod(n, 10)
|
| 88 |
+
return _H10[t] if u == 0 else _H10[t] + " da " + _H1[u]
|
| 89 |
+
for v, w in ((10 ** 9, "biliyan"), (10 ** 6, "miliyan"), (1000, "dubu"), (100, "ɗari")):
|
| 90 |
+
if n >= v:
|
| 91 |
+
q, r = divmod(n, v)
|
| 92 |
+
s = w if q == 1 else w + " " + hau(q)
|
| 93 |
+
return s if r == 0 else s + " da " + hau(r)
|
| 94 |
+
return str(n)
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
# ------------------------------------------------------------------ Yorùbá
|
| 98 |
+
# counting forms 1-10, then vigesimal/subtractive 11-99 (standard grammar tables); decimal composition >= 100
|
| 99 |
+
_Y1 = ["òdo", "oókan", "eéjì", "ẹẹ́ta", "ẹẹ́rin", "aárùn-ún", "ẹẹ́fà", "eéje", "ẹẹ́jọ", "ẹẹ́sàn-án", "ẹẹ́wàá"]
|
| 100 |
+
_Y11 = {11: "ọ̀kanlá", 12: "èjìlá", 13: "ẹ̀tàlá", 14: "ẹ̀rìnlá"}
|
| 101 |
+
# tens: name, locative form used after lé/dín ("added to / less than")
|
| 102 |
+
_YT = {20: ("ogún", "lógún"), 30: ("ọgbọ̀n", "lọ́gbọ̀n"), 40: ("ogójì", "lógójì"), 50: ("àádọ́ta", "láàádọ́ta"),
|
| 103 |
+
60: ("ọgọ́ta", "lọ́gọ́ta"), 70: ("àádọ́rin", "láàádọ́rin"), 80: ("ọgọ́rin", "lọ́gọ́rin"),
|
| 104 |
+
90: ("àádọ́rùn-ún", "láàádọ́rùn-ún"), 100: ("ọgọ́rùn-ún", "lọ́gọ́rùn-ún")}
|
| 105 |
+
_YLE = {1: "ọ̀kàn", 2: "éjì", 3: "ẹ́tà", 4: "ẹ́rìn"} # +1..+4
|
| 106 |
+
_YDIN = {1: "ọ̀kàn", 2: "éjì", 3: "ẹẹ́tà", 4: "ẹẹ́rìn"} # -1..-4
|
| 107 |
+
_YFIVE = {20: "ẹ̀ẹ́dógún", 30: "ẹ̀ẹ́dọ́gbọ̀n", 40: "ẹ̀ẹ́dógójì", 50: "ẹ̀ẹ́dáàádọ́ta", 60: "ẹ̀ẹ́dọ́gọ́ta", 70: "ẹ̀ẹ́dáàádọ́rin",
|
| 108 |
+
80: "ẹ̀ẹ́dọ́gọ́rin", 90: "ẹ̀ẹ́dáàádọ́rùn-ún", 100: "ẹ̀ẹ́dọ́gọ́rùn-ún"} # (T - 5)
|
| 109 |
+
_YADJ = {1: "kan", 2: "méjì", 3: "mẹ́ta", 4: "mẹ́rin", 5: "márùn-ún", 6: "mẹ́fà", 7: "méje", 8: "mẹ́jọ", 9: "mẹ́sàn-án", 10: "mẹ́wàá"}
|
| 110 |
+
_YH = {200: "igba", 300: "ọ̀ọ́dúnrún", 400: "irinwó", 500: "ẹ̀ẹ́dẹ́gbẹ̀ta", 600: "ẹgbẹ̀ta", 700: "ẹ̀ẹ́dẹ́gbẹ̀rin",
|
| 111 |
+
800: "ẹgbẹ̀rin", 900: "ẹ̀ẹ́dẹ́gbẹ̀rún"}
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
def _y99(n):
|
| 115 |
+
if n <= 10:
|
| 116 |
+
return _Y1[n]
|
| 117 |
+
if n in _Y11:
|
| 118 |
+
return _Y11[n]
|
| 119 |
+
if n in _YT:
|
| 120 |
+
return _YT[n][0]
|
| 121 |
+
T = (n // 10) * 10
|
| 122 |
+
u = n - T
|
| 123 |
+
if u <= 4: # T + u (u-lé-T)
|
| 124 |
+
return _YLE[u] + "lé" + _YT[T][1]
|
| 125 |
+
if u == 5: # (T+10) - 5
|
| 126 |
+
return _YFIVE[T + 10]
|
| 127 |
+
return _YDIN[10 - u] + "dín" + _YT[T + 10][1] # (T+10) - (10-u)
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
def yor(n):
|
| 131 |
+
if n < 100:
|
| 132 |
+
return _y99(n)
|
| 133 |
+
if n < 1000:
|
| 134 |
+
h, r = divmod(n, 100)
|
| 135 |
+
s = _YT[100][0] if h == 1 else _YH[h * 100]
|
| 136 |
+
return s if r == 0 else s + " ó lé " + _y99(r)
|
| 137 |
+
for v, w in ((10 ** 9, "bílíọ̀nù"), (10 ** 6, "mílíọ̀nù"), (1000, "ẹgbẹ̀rún")):
|
| 138 |
+
if n >= v:
|
| 139 |
+
q, r = divmod(n, v)
|
| 140 |
+
s = w + " " + (_YADJ[q] if q in _YADJ else yor(q))
|
| 141 |
+
return s if r == 0 else s + " ó lé " + yor(r)
|
| 142 |
+
return str(n)
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
NUM = {"eng": eng, "pcm": eng, "ibo": ibo, "hau": hau, "yor": yor}
|
| 146 |
+
|
| 147 |
+
MONTHS = {
|
| 148 |
+
"eng": "January February March April May June July August September October November December".split(),
|
| 149 |
+
"ibo": "Jenụwarị Febụwarị Maachị Epreel Mee Juun Julaị Ọgọọst Septemba Ọktoba Novemba Disemba".split(),
|
| 150 |
+
"hau": "Janairu Fabrairu Maris Afrilu Mayu Yuni Yuli Agusta Satumba Oktoba Nuwamba Disamba".split(),
|
| 151 |
+
"yor": "Ṣẹ́rẹ́ Èrèlé Ẹrẹ̀nà Ìgbé Ẹ̀bìbí Òkúdu Agẹmọ Ògún Owewe Ọ̀wàrà Bélú Ọ̀pẹ̀".split(),
|
| 152 |
+
}
|
| 153 |
+
MONTHS["pcm"] = MONTHS["eng"]
|
| 154 |
+
_MIDX = {m.lower(): i for i, m in enumerate(MONTHS["eng"])}
|
| 155 |
+
_MIDX.update({m[:3].lower(): i for i, m in enumerate(MONTHS["eng"])})
|
| 156 |
+
|
| 157 |
+
CUR = { # (major, minor) per language; phrase order handled in money()
|
| 158 |
+
"NGN": {"eng": ("naira", "kobo"), "pcm": ("naira", "kobo"), "ibo": ("naịra", "kobo"), "hau": ("naira", "kobo"), "yor": ("náírà", "kọ́bọ̀")},
|
| 159 |
+
"USD": {"eng": ("dollars", "cents"), "pcm": ("dollars", "cents"), "ibo": ("dọla", "senti"), "hau": ("dala", "santi"), "yor": ("dọ́là", "sẹ́ǹtì")},
|
| 160 |
+
"GBP": {"eng": ("pounds", "pence"), "pcm": ("pounds", "pence"), "ibo": ("paụnd", "pens"), "hau": ("fam", "fens"), "yor": ("pọ́n-ùn", "pẹ́ńsì")},
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
|
| 164 |
+
def num(n, lang):
|
| 165 |
+
return NUM[lang](n) if n < 10 ** 9 else str(n)
|
| 166 |
+
|
| 167 |
+
|
| 168 |
+
def money(amount, code, lang):
|
| 169 |
+
whole, _, frac = amount.partition(".")
|
| 170 |
+
whole = int(whole.replace(",", "") or 0)
|
| 171 |
+
major, minor = CUR[code][lang]
|
| 172 |
+
if lang in ("eng", "pcm"):
|
| 173 |
+
s = f"{num(whole, lang)} {major}"
|
| 174 |
+
if code == "USD" and whole == 1:
|
| 175 |
+
s = "one dollar"
|
| 176 |
+
if frac and int(frac[:2].ljust(2, "0")):
|
| 177 |
+
s += f" {num(int(frac[:2].ljust(2, '0')), lang)} {minor}"
|
| 178 |
+
return s
|
| 179 |
+
s = f"{major} {num(whole, lang)}" # ibo/hau/yor: currency word first ("naịra puku ise")
|
| 180 |
+
if lang == "yor":
|
| 181 |
+
s = f"{major} {yor_adj(whole)}"
|
| 182 |
+
if frac and int(frac[:2].ljust(2, "0")):
|
| 183 |
+
k = int(frac[:2].ljust(2, "0"))
|
| 184 |
+
s += {"ibo": " na ", "hau": " da ", "yor": " ó lé "}[lang] + f"{minor} {yor_adj(k) if lang == 'yor' else num(k, lang)}"
|
| 185 |
+
return s
|
| 186 |
+
|
| 187 |
+
|
| 188 |
+
def yor_adj(n):
|
| 189 |
+
"""Yorùbá number after a noun (adjectival form for 1-10, counting form otherwise)."""
|
| 190 |
+
return _YADJ.get(n) or yor(n)
|
| 191 |
+
|
| 192 |
+
|
| 193 |
+
def date(d, m, y, lang):
|
| 194 |
+
M = MONTHS[lang][m - 1]
|
| 195 |
+
if lang in ("eng", "pcm"):
|
| 196 |
+
return f"the {eng_ord(d)} of {M}" + (f", {eng_year(y)}" if y else "")
|
| 197 |
+
if lang == "ibo":
|
| 198 |
+
return f"ụbọchị {ibo(d)} n'ọnwa {M}" + (f", afọ {ibo(y)}" if y else "")
|
| 199 |
+
if lang == "hau":
|
| 200 |
+
return f"ranar {hau(d)} ga watan {M}" + (f", shekarar {hau(y)}" if y else "")
|
| 201 |
+
return f"ọjọ́ {yor(d)} oṣù {M}" + (f", ọdún {yor(y)}" if y else "")
|
| 202 |
+
|
| 203 |
+
|
| 204 |
+
def clock(h, mi, lang):
|
| 205 |
+
if lang in ("eng", "pcm"):
|
| 206 |
+
return eng(h) + ("" if mi == 0 else (" oh " + eng(mi) if mi < 10 else " " + eng(mi))) + (" o'clock" if mi == 0 else "")
|
| 207 |
+
if lang == "ibo":
|
| 208 |
+
return f"elekere {ibo(h)}" + ("" if mi == 0 else f" na nkeji {ibo(mi)}")
|
| 209 |
+
if lang == "hau":
|
| 210 |
+
return f"ƙarfe {hau(h)}" + ("" if mi == 0 else f" da minti {hau(mi)}")
|
| 211 |
+
return f"agogo {yor_adj(h)}" + ("" if mi == 0 else f" ó lé ìṣẹ́jú {yor_adj(mi)}")
|
| 212 |
+
|
| 213 |
+
|
| 214 |
+
def percent(x, lang):
|
| 215 |
+
w = decimal(x, lang)
|
| 216 |
+
return {"eng": f"{w} percent", "pcm": f"{w} percent", "ibo": f"pasentị {w}", "hau": f"kashi {w} cikin ɗari",
|
| 217 |
+
"yor": f"ìdá {w} nínú ọgọ́rùn-ún"}[lang]
|
| 218 |
+
|
| 219 |
+
|
| 220 |
+
_POINT = {"eng": "point", "pcm": "point", "ibo": "ntụpọ", "hau": "digo", "yor": "ààmì"}
|
| 221 |
+
|
| 222 |
+
|
| 223 |
+
def decimal(x, lang):
|
| 224 |
+
a, _, b = x.replace(",", "").partition(".")
|
| 225 |
+
s = num(int(a or 0), lang)
|
| 226 |
+
if b:
|
| 227 |
+
s += f" {_POINT[lang]} " + " ".join(num(int(c), lang) for c in b)
|
| 228 |
+
return s
|
| 229 |
+
|
| 230 |
+
|
| 231 |
+
_AMT = r"\d{1,3}(?:,\d{3})+(?:\.\d+)?|\d+(?:\.\d+)?"
|
| 232 |
+
_RE_MONEY = re.compile(r"(?:(₦|NGN\s?|N(?=\d)|\$|USD\s?|£)\s?(" + _AMT + r")(\s?(?:k|m|bn)\b)?)|(?:(" + _AMT + r")\s?(naira|kobo|dollars?)\b)", re.I)
|
| 233 |
+
_RE_DATE = re.compile(r"\b(\d{1,2})[/.-](\d{1,2})[/.-](\d{4})\b")
|
| 234 |
+
_RE_DATE2 = re.compile(r"\b(\d{1,2})(?:st|nd|rd|th)?\s+(January|February|March|April|May|June|July|August|September|October|November|December|Jan|Feb|Mar|Apr|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)\.?,?\s*(\d{4})?\b", re.I)
|
| 235 |
+
_RE_TIME = re.compile(r"\b(\d{1,2}):(\d{2})(?:\s?(am|pm)\b)?", re.I)
|
| 236 |
+
_RE_TIME2 = re.compile(r"\b(\d{1,2})\s?(am|pm)\b", re.I)
|
| 237 |
+
_RE_PCT = re.compile(r"(" + _AMT + r")\s?%")
|
| 238 |
+
_RE_ORD = re.compile(r"\b(\d+)(st|nd|rd|th)\b", re.I)
|
| 239 |
+
_RE_YEAR = re.compile(r"\b(1[5-9]\d\d|20\d\d)\b")
|
| 240 |
+
_RE_NUM = re.compile(_AMT)
|
| 241 |
+
_DUP = re.compile(r"\b(n'elekere|elekere|karfe|ƙarfe|ranar|agogo|ọjọ́|ụbọchị)\s+(elekere|ƙarfe|ranar|agogo|ọjọ́|ụbọchị)\b", re.I)
|
| 242 |
+
_SCALE = {"k": 1000, "m": 10 ** 6, "bn": 10 ** 9}
|
| 243 |
+
|
| 244 |
+
|
| 245 |
+
def normalize(text, lang):
|
| 246 |
+
"""Verbalise numbers etc. for one language segment (no <lang> tags inside)."""
|
| 247 |
+
lang = lang if lang in NUM else "eng"
|
| 248 |
+
t = unicodedata.normalize("NFC", text)
|
| 249 |
+
|
| 250 |
+
def _money(m):
|
| 251 |
+
if m.group(1):
|
| 252 |
+
sym, amt, sc = m.group(1).strip().upper(), m.group(2), (m.group(3) or "").strip().lower()
|
| 253 |
+
code = {"₦": "NGN", "N": "NGN", "NGN": "NGN", "$": "USD", "USD": "USD", "£": "GBP"}[sym]
|
| 254 |
+
else:
|
| 255 |
+
amt, word, sc = m.group(4), m.group(5).lower(), ""
|
| 256 |
+
if word == "kobo":
|
| 257 |
+
k = int(amt.replace(",", ""))
|
| 258 |
+
return f"{num(k, lang)} kobo" if lang in ("eng", "pcm") else f"{CUR['NGN'][lang][1]} {yor_adj(k) if lang == 'yor' else num(k, lang)}"
|
| 259 |
+
code = "NGN" if word == "naira" else "USD"
|
| 260 |
+
if sc:
|
| 261 |
+
amt = str(int(round(float(amt.replace(",", "")) * _SCALE[sc])))
|
| 262 |
+
return money(amt, code, lang)
|
| 263 |
+
|
| 264 |
+
t = _RE_MONEY.sub(_money, t)
|
| 265 |
+
t = _RE_PCT.sub(lambda m: percent(m.group(1), lang), t)
|
| 266 |
+
t = _RE_DATE.sub(lambda m: date(int(m.group(1)), int(m.group(2)), int(m.group(3)), lang)
|
| 267 |
+
if 1 <= int(m.group(1)) <= 31 and 1 <= int(m.group(2)) <= 12 else m.group(0), t)
|
| 268 |
+
t = _RE_DATE2.sub(lambda m: date(int(m.group(1)), _MIDX[m.group(2).lower()[:3]] + 1,
|
| 269 |
+
int(m.group(3)) if m.group(3) else None, lang), t)
|
| 270 |
+
|
| 271 |
+
def _time(m):
|
| 272 |
+
h, mi, ap = int(m.group(1)), int(m.group(2)), (m.group(3) or "").lower()
|
| 273 |
+
s = clock(h, mi, lang)
|
| 274 |
+
if ap and lang in ("eng", "pcm"):
|
| 275 |
+
s += " " + {"am": "a m", "pm": "p m"}[ap]
|
| 276 |
+
return s
|
| 277 |
+
|
| 278 |
+
t = _RE_TIME.sub(_time, t)
|
| 279 |
+
t = _RE_TIME2.sub(lambda m: (eng(int(m.group(1))) + " " + {"am": "a m", "pm": "p m"}[m.group(2).lower()])
|
| 280 |
+
if lang in ("eng", "pcm") else clock(int(m.group(1)), 0, lang), t)
|
| 281 |
+
if lang in ("eng", "pcm"):
|
| 282 |
+
t = _RE_ORD.sub(lambda m: eng_ord(int(m.group(1))), t)
|
| 283 |
+
t = _RE_YEAR.sub(lambda m: eng_year(int(m.group(1))), t)
|
| 284 |
+
else:
|
| 285 |
+
t = _RE_ORD.sub(lambda m: num(int(m.group(1)), lang), t)
|
| 286 |
+
t = _RE_NUM.sub(lambda m: decimal(m.group(0), lang) if "." in m.group(0) else num(int(m.group(0).replace(",", "")), lang), t)
|
| 287 |
+
t = _DUP.sub(lambda m: m.group(1) if m.group(1).lower().endswith(m.group(2).lower()) or m.group(1).lower() == "karfe" else m.group(0), t)
|
| 288 |
+
return re.sub(r"\s+", " ", t).strip()
|
| 289 |
+
|
| 290 |
+
|
| 291 |
+
def normalize_tagged(text, default="eng"):
|
| 292 |
+
"""Apply normalize() to every <lang>…</lang> segment of a tagged string (untagged text uses `default`)."""
|
| 293 |
+
out, pos = [], 0
|
| 294 |
+
for m in re.finditer(r"<(\w{3})>(.*?)</\1>", text, re.S):
|
| 295 |
+
if m.start() > pos:
|
| 296 |
+
out.append(normalize(text[pos:m.start()], default) if text[pos:m.start()].strip() else text[pos:m.start()])
|
| 297 |
+
out.append(f"<{m.group(1)}>{normalize(m.group(2), m.group(1))}</{m.group(1)}>")
|
| 298 |
+
pos = m.end()
|
| 299 |
+
if pos < len(text):
|
| 300 |
+
rest = text[pos:]
|
| 301 |
+
out.append(normalize(rest, default) if rest.strip() else rest)
|
| 302 |
+
return "".join(out)
|
| 303 |
+
|
| 304 |
+
|
| 305 |
+
if __name__ == "__main__":
|
| 306 |
+
import sys
|
| 307 |
+
for L in ["eng", "pcm", "ibo", "hau", "yor"]:
|
| 308 |
+
print(L, "|", normalize("₦5,000 on 21/10/2026 at 7:30, 45% of 1,235 people, 3.5 km", L))
|
infer.py
CHANGED
|
@@ -1,7 +1,12 @@
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
-
"""Dynamic Accent: Nigerian multilingual, code-switching TTS
|
| 3 |
|
| 4 |
Versions (`--version`):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
phase2 LM `p2_lm_B` + anchor-SFT flow `p2_flow_sft`. Phase 2 sampler, sentence stitching, edge trim, internal
|
| 6 |
silences capped at 0.6 s, 0.6 s between sentences (exactly the Phase 2 final samples).
|
| 7 |
phase3 LM `p3_lm_full` (re-cut long-form data with natural pauses, ~102 h of Igbo) + the shared Phase 2 flow (see
|
|
@@ -14,7 +19,7 @@ Voices (`--voice`): `anchor_male` (default; WAXAL Yoruba speaker 4), `waxal_ibo_
|
|
| 14 |
speaker token is used when the LM was trained on that speaker.
|
| 15 |
|
| 16 |
python infer.py --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --version phase3 --out out.wav
|
| 17 |
-
python infer.py --text "..." --compare --out cmp.wav # -> cmp_phase2.wav
|
| 18 |
python infer.py --list_voices
|
| 19 |
python infer.py --auto_tag --tag_only --text "Omo, this traffic no be here o. Ẹ ṣé púpọ̀." # inspect / edit the tags
|
| 20 |
|
|
@@ -382,10 +387,75 @@ def version_cfg(name):
|
|
| 382 |
cj = os.path.join(HERE, os.path.dirname(cfg["lm"]), "config.json")
|
| 383 |
if os.path.exists(cj): # a checkpoint may override flow / rate / sampler
|
| 384 |
cfg.update({k: v for k, v in json.load(open(cj)).items() if k in cfg})
|
| 385 |
-
|
|
|
|
|
|
|
| 386 |
return cfg
|
| 387 |
|
| 388 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 389 |
def word_chunks(text, max_words=60):
|
| 390 |
"""one pass per <= max_words, split only at sentence ends (a whole paragraph usually fits in one pass)."""
|
| 391 |
sents = split_sentences(text)
|
|
@@ -522,6 +592,8 @@ class DynamicAccent:
|
|
| 522 |
|
| 523 |
def build(version, a, cosy=None, tok=None, copy_llm=False):
|
| 524 |
cfg = version_cfg(version)
|
|
|
|
|
|
|
| 525 |
lm = a.lm or cfg["lm"]; flow = a.flow or cfg["flow"]
|
| 526 |
S = DynamicAccent(a.model_dir, a.cosyvoice_dir, lm, flow, a.prompts, a.dtype, sampler=cfg["sampler"],
|
| 527 |
one_pass=cfg["one_pass"] and not a.stitch, postprocess=cfg["postprocess"],
|
|
@@ -539,8 +611,7 @@ def list_voices(voices_json):
|
|
| 539 |
for k, v in SETTINGS.get("versions", {}).items():
|
| 540 |
print(f" {k:20s} {v.get('desc', '')}")
|
| 541 |
if RECOMMENDED:
|
| 542 |
-
print("\nrecommended pairing:
|
| 543 |
-
"; phase2 -> " + ", ".join(RECOMMENDED.get("phase2", [])))
|
| 544 |
print(" " + RECOMMENDED.get("note", ""))
|
| 545 |
|
| 546 |
|
|
@@ -564,14 +635,25 @@ def main():
|
|
| 564 |
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 565 |
ap.add_argument("--text", help="text; tagged ('<eng>Good morning,</eng> <pcm>how body?</pcm>') or plain with --auto_tag")
|
| 566 |
ap.add_argument("--version", default=SETTINGS.get("default_version", "phase3"), choices=sorted(VERSIONS),
|
| 567 |
-
help="model version (default phase3)")
|
| 568 |
ap.add_argument("--compare", action="store_true",
|
| 569 |
-
help="render the same text, seed and voice with
|
|
|
|
| 570 |
ap.add_argument("--voice", default=SETTINGS.get("default_voice", "anchor_male"),
|
| 571 |
help="anchor_male | waxal_ibo_5_female | waxal_yor_5_female (see --list_voices)")
|
| 572 |
ap.add_argument("--list_voices", action="store_true", help="list voices, versions and the recommended pairing")
|
| 573 |
ap.add_argument("--rate", default="default", choices=["default", "none", "very slow", "slow", "normal", "fast", "very fast"],
|
| 574 |
-
help="phase3 speed instruction to the LM (default: the version's setting, 'normal'; 'none' = no instruction)")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 575 |
# code-switching control
|
| 576 |
ap.add_argument("--auto_tag", action="store_true",
|
| 577 |
help="tag untagged mixed text automatically (word/span language ID), print it, then synthesise")
|
|
@@ -607,10 +689,13 @@ def main():
|
|
| 607 |
print(f"[tagged] {text}")
|
| 608 |
if a.tag_only:
|
| 609 |
return
|
| 610 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 611 |
from huggingface_hub import snapshot_download
|
| 612 |
snapshot_download("FunAudioLLM/CosyVoice2-0.5B", local_dir=a.model_dir)
|
| 613 |
-
versions = ["phase2", "phase3"] if a.compare else [a.version]
|
| 614 |
cosy = tok = None
|
| 615 |
base, ext = os.path.splitext(a.out)
|
| 616 |
for v in versions:
|
|
@@ -618,13 +703,17 @@ def main():
|
|
| 618 |
if hint:
|
| 619 |
print(hint)
|
| 620 |
S = build(v, a, cosy, tok)
|
| 621 |
-
|
|
|
|
| 622 |
w = S.say(text, seed=a.seed, prompt_k=a.prompt_clip, stitch=not a.no_stitch, pause_mode=a.pause_mode,
|
| 623 |
speed=a.speed if v == "phase2" else 1.0)
|
| 624 |
out = f"{base}_{v}{ext or '.wav'}" if a.compare else a.out
|
| 625 |
sf.write(out, w, S.sr)
|
| 626 |
print(f"[{v}] wrote {out} ({len(w) / S.sr:.2f} s, {S.sr} Hz, voice={a.voice}, device={DEV.type})")
|
| 627 |
-
del S.m
|
|
|
|
|
|
|
|
|
|
| 628 |
|
| 629 |
|
| 630 |
if __name__ == "__main__":
|
|
|
|
| 1 |
#!/usr/bin/env python
|
| 2 |
+
"""Dynamic Accent: Nigerian multilingual, code-switching TTS, with selectable model versions.
|
| 3 |
|
| 4 |
Versions (`--version`):
|
| 5 |
+
flash (default) LM `checkpoints/flash/flash_dpo` on Fun-CosyVoice3-0.5B-2512 (Apache-2.0): Flash SFT + DPO preference
|
| 6 |
+
tuning (naturalness + CER + pace + pause reward), licensed data only. CV3 base flow/vocoder, zero-shot from the
|
| 7 |
+
voice clip. Text front-end: numbers verbalised, Yoruba/Igbo diacritics restored when missing (ByT5 model in
|
| 8 |
+
checkpoints/flash/diacritics_byt5). One pass per paragraph (<= ~60 words), model pauses, no post-processing.
|
| 9 |
+
Needs a CUDA GPU and a CosyVoice clone with CosyVoice3 support.
|
| 10 |
phase2 LM `p2_lm_B` + anchor-SFT flow `p2_flow_sft`. Phase 2 sampler, sentence stitching, edge trim, internal
|
| 11 |
silences capped at 0.6 s, 0.6 s between sentences (exactly the Phase 2 final samples).
|
| 12 |
phase3 LM `p3_lm_full` (re-cut long-form data with natural pauses, ~102 h of Igbo) + the shared Phase 2 flow (see
|
|
|
|
| 19 |
speaker token is used when the LM was trained on that speaker.
|
| 20 |
|
| 21 |
python infer.py --text "<eng>this is dynamic accent,</eng> <pcm>e dey sound nice abi?</pcm>" --version phase3 --out out.wav
|
| 22 |
+
python infer.py --text "..." --compare --out cmp.wav # -> cmp_phase2/phase3/flash.wav, same text, seed, voice
|
| 23 |
python infer.py --list_voices
|
| 24 |
python infer.py --auto_tag --tag_only --text "Omo, this traffic no be here o. Ẹ ṣé púpọ̀." # inspect / edit the tags
|
| 25 |
|
|
|
|
| 387 |
cj = os.path.join(HERE, os.path.dirname(cfg["lm"]), "config.json")
|
| 388 |
if os.path.exists(cj): # a checkpoint may override flow / rate / sampler
|
| 389 |
cfg.update({k: v for k, v in json.load(open(cj)).items() if k in cfg})
|
| 390 |
+
for k in ("lm", "flow", "diacritics"):
|
| 391 |
+
if cfg.get(k):
|
| 392 |
+
cfg[k] = os.path.join(HERE, cfg[k])
|
| 393 |
return cfg
|
| 394 |
|
| 395 |
|
| 396 |
+
# ------------------------------------------------------------------ Flash (CosyVoice3 engine)
|
| 397 |
+
FLASH_VOICE = {"anchor_male": "anchor", "waxal_ibo_5_female": "waxal_ibo_5", "waxal_yor_5_female": "waxal_yor_5"}
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
def canonical_voice(voice, voices_json=None):
|
| 401 |
+
try:
|
| 402 |
+
al = json.load(open(voices_json, encoding="utf-8")).get("aliases", {}) if voices_json else {}
|
| 403 |
+
except OSError:
|
| 404 |
+
al = {}
|
| 405 |
+
return al.get(voice, voice)
|
| 406 |
+
|
| 407 |
+
|
| 408 |
+
class FlashTTS:
|
| 409 |
+
"""--version flash: CosyVoice3 base + Flash-DPO LM (flash_lm.Synth) behind the same say()/sr interface."""
|
| 410 |
+
|
| 411 |
+
def __init__(self, a, cfg):
|
| 412 |
+
if not torch.cuda.is_available():
|
| 413 |
+
raise SystemExit("--version flash needs a CUDA GPU (phase2/phase3 also run on CPU)")
|
| 414 |
+
cv3 = getattr(a, "cv3_dir", "") or os.environ.get("CV3_DIR") or os.path.join(HERE, "pretrained", "Fun-CosyVoice3-0.5B-2512")
|
| 415 |
+
if not os.path.isdir(cv3):
|
| 416 |
+
from huggingface_hub import snapshot_download
|
| 417 |
+
snapshot_download("FunAudioLLM/Fun-CosyVoice3-0.5B-2512", local_dir=cv3)
|
| 418 |
+
os.environ["CV3_DIR"] = cv3
|
| 419 |
+
os.environ.setdefault("COSYVOICE_REPO", a.cosyvoice_dir)
|
| 420 |
+
os.environ.setdefault("DA_PROMPTS", os.path.join(HERE, "prompts"))
|
| 421 |
+
import flash_lm
|
| 422 |
+
self.S = flash_lm.Synth(a.lm or cfg["lm"])
|
| 423 |
+
self.cosy = self.tok = None # not shareable with the CosyVoice2 versions
|
| 424 |
+
self.m = self.S.m
|
| 425 |
+
self.sr = self.S.cosy.sample_rate
|
| 426 |
+
r = a.rate if a.rate != "default" else cfg.get("rate", "normal")
|
| 427 |
+
self.rate = RATES.index(None if r == "none" else r) if (None if r == "none" else r) in RATES else 0
|
| 428 |
+
self.fe_mode = getattr(a, "frontend", "codeswitch")
|
| 429 |
+
self.fe_lang = getattr(a, "frontend_lang", "eng")
|
| 430 |
+
if self.fe_mode == "translate" and not getattr(a, "experimental_translate", False):
|
| 431 |
+
raise SystemExit("--frontend translate is EXPERIMENTAL and off by default (MADLAD-400 loops on long inputs and is "
|
| 432 |
+
"weak on Pidgin). Add --experimental_translate to use it anyway.")
|
| 433 |
+
from frontend import FrontEnd
|
| 434 |
+
diac = cfg.get("diacritics") if not getattr(a, "no_diacritics", False) else None
|
| 435 |
+
self.fe = FrontEnd(diac if diac and os.path.isdir(diac) else None, mt=self.fe_mode == "translate")
|
| 436 |
+
self.set_voice(a.voice, a.voices)
|
| 437 |
+
|
| 438 |
+
def set_voice(self, voice, voices_json=None):
|
| 439 |
+
v = canonical_voice(voice, voices_json)
|
| 440 |
+
if v not in FLASH_VOICE:
|
| 441 |
+
raise SystemExit(f"unknown voice '{voice}' for flash; available: {', '.join(FLASH_VOICE)}")
|
| 442 |
+
self.voice = FLASH_VOICE[v]
|
| 443 |
+
|
| 444 |
+
def frontend(self, text):
|
| 445 |
+
return self.fe(text, self.fe_mode, self.fe_lang)
|
| 446 |
+
|
| 447 |
+
def say(self, tagged_text, seed=0, return_info=False, **_):
|
| 448 |
+
t = self.frontend(tagged_text)
|
| 449 |
+
print(f"[flash front-end] {t}")
|
| 450 |
+
rate = RATES[self.rate]
|
| 451 |
+
ws = []
|
| 452 |
+
for i, ch in enumerate(word_chunks(t)):
|
| 453 |
+
toks = self.S.tokens(ch, self.voice, rate or "none", seed + 1000 * i)[0]
|
| 454 |
+
ws.append(self.S.wav(toks, self.voice))
|
| 455 |
+
w = np.concatenate(ws).astype(np.float32)
|
| 456 |
+
return (w, None) if return_info else w
|
| 457 |
+
|
| 458 |
+
|
| 459 |
def word_chunks(text, max_words=60):
|
| 460 |
"""one pass per <= max_words, split only at sentence ends (a whole paragraph usually fits in one pass)."""
|
| 461 |
sents = split_sentences(text)
|
|
|
|
| 592 |
|
| 593 |
def build(version, a, cosy=None, tok=None, copy_llm=False):
|
| 594 |
cfg = version_cfg(version)
|
| 595 |
+
if cfg.get("engine") == "cosyvoice3":
|
| 596 |
+
return FlashTTS(a, cfg)
|
| 597 |
lm = a.lm or cfg["lm"]; flow = a.flow or cfg["flow"]
|
| 598 |
S = DynamicAccent(a.model_dir, a.cosyvoice_dir, lm, flow, a.prompts, a.dtype, sampler=cfg["sampler"],
|
| 599 |
one_pass=cfg["one_pass"] and not a.stitch, postprocess=cfg["postprocess"],
|
|
|
|
| 611 |
for k, v in SETTINGS.get("versions", {}).items():
|
| 612 |
print(f" {k:20s} {v.get('desc', '')}")
|
| 613 |
if RECOMMENDED:
|
| 614 |
+
print("\nrecommended pairing: " + "; ".join(f"{k} -> {', '.join(v)}" for k, v in RECOMMENDED.items() if isinstance(v, list)))
|
|
|
|
| 615 |
print(" " + RECOMMENDED.get("note", ""))
|
| 616 |
|
| 617 |
|
|
|
|
| 635 |
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
| 636 |
ap.add_argument("--text", help="text; tagged ('<eng>Good morning,</eng> <pcm>how body?</pcm>') or plain with --auto_tag")
|
| 637 |
ap.add_argument("--version", default=SETTINGS.get("default_version", "phase3"), choices=sorted(VERSIONS),
|
| 638 |
+
help=f"model version (default {SETTINGS.get('default_version', 'phase3')})")
|
| 639 |
ap.add_argument("--compare", action="store_true",
|
| 640 |
+
help="render the same text, seed and voice with every version in --compare_versions -> <out>_<version>.wav")
|
| 641 |
+
ap.add_argument("--compare_versions", default="phase2,phase3,flash", help="versions for --compare (comma-separated)")
|
| 642 |
ap.add_argument("--voice", default=SETTINGS.get("default_voice", "anchor_male"),
|
| 643 |
help="anchor_male | waxal_ibo_5_female | waxal_yor_5_female (see --list_voices)")
|
| 644 |
ap.add_argument("--list_voices", action="store_true", help="list voices, versions and the recommended pairing")
|
| 645 |
ap.add_argument("--rate", default="default", choices=["default", "none", "very slow", "slow", "normal", "fast", "very fast"],
|
| 646 |
+
help="phase3/flash speed instruction to the LM (default: the version's setting, 'normal'; 'none' = no instruction)")
|
| 647 |
+
# flash text front-end
|
| 648 |
+
ap.add_argument("--frontend", default="codeswitch", choices=["codeswitch", "native", "accent", "translate"],
|
| 649 |
+
help="flash only: codeswitch (tagged/one-language text), native (whole text in --frontend_lang), accent "
|
| 650 |
+
"(words as written, read with the --frontend_lang accent), translate (EXPERIMENTAL, off by default)")
|
| 651 |
+
ap.add_argument("--frontend_lang", default="eng", choices=LANGS, help="flash front-end language for untagged text / native / accent / translate target")
|
| 652 |
+
ap.add_argument("--no_diacritics", action="store_true", help="flash: do not restore missing Yoruba/Igbo diacritics")
|
| 653 |
+
ap.add_argument("--experimental_translate", action="store_true",
|
| 654 |
+
help="flash: allow --frontend translate (MADLAD-400-3B-MT, ~12 GB download; loops on long inputs, weak on Pidgin)")
|
| 655 |
+
ap.add_argument("--cv3_dir", default=os.environ.get("CV3_DIR", os.path.join(HERE, "pretrained", "Fun-CosyVoice3-0.5B-2512")),
|
| 656 |
+
help="flash: stock FunAudioLLM/Fun-CosyVoice3-0.5B-2512 snapshot (downloaded on first run)")
|
| 657 |
# code-switching control
|
| 658 |
ap.add_argument("--auto_tag", action="store_true",
|
| 659 |
help="tag untagged mixed text automatically (word/span language ID), print it, then synthesise")
|
|
|
|
| 689 |
print(f"[tagged] {text}")
|
| 690 |
if a.tag_only:
|
| 691 |
return
|
| 692 |
+
versions = [v.strip() for v in a.compare_versions.split(",") if v.strip()] if a.compare else [a.version]
|
| 693 |
+
bad = [v for v in versions if v not in VERSIONS]
|
| 694 |
+
if bad:
|
| 695 |
+
ap.error(f"unknown version(s) {bad}; available: {sorted(VERSIONS)}")
|
| 696 |
+
if any(VERSIONS[v].get("engine") != "cosyvoice3" for v in versions) and not os.path.isdir(a.model_dir):
|
| 697 |
from huggingface_hub import snapshot_download
|
| 698 |
snapshot_download("FunAudioLLM/CosyVoice2-0.5B", local_dir=a.model_dir)
|
|
|
|
| 699 |
cosy = tok = None
|
| 700 |
base, ext = os.path.splitext(a.out)
|
| 701 |
for v in versions:
|
|
|
|
| 703 |
if hint:
|
| 704 |
print(hint)
|
| 705 |
S = build(v, a, cosy, tok)
|
| 706 |
+
if S.cosy is not None:
|
| 707 |
+
cosy, tok = S.cosy, S.tok
|
| 708 |
w = S.say(text, seed=a.seed, prompt_k=a.prompt_clip, stitch=not a.no_stitch, pause_mode=a.pause_mode,
|
| 709 |
speed=a.speed if v == "phase2" else 1.0)
|
| 710 |
out = f"{base}_{v}{ext or '.wav'}" if a.compare else a.out
|
| 711 |
sf.write(out, w, S.sr)
|
| 712 |
print(f"[{v}] wrote {out} ({len(w) / S.sr:.2f} s, {S.sr} Hz, voice={a.voice}, device={DEV.type})")
|
| 713 |
+
del S.m
|
| 714 |
+
if isinstance(S, FlashTTS):
|
| 715 |
+
del S.S
|
| 716 |
+
del S; torch.cuda.empty_cache()
|
| 717 |
|
| 718 |
|
| 719 |
if __name__ == "__main__":
|
prompts/flash_voices_text.json
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{"anchor": "<yor>Púpọ̀ jùlọ àwọn olókìkí ní ìlú Èkó ń gbé ní erékùṣù náà.</yor>",
|
| 2 |
+
"waxal_ibo_5": "<ibo>I nwere ike itinye mmemme ọbụla n'izu a ma gị atụla ụjọ maka oké mmiri ozuzo.</ibo>",
|
| 3 |
+
"waxal_yor_5": "<yor>Nínú oṣù Ọpẹ́ ni ó ra mọ́tò tí wọ́n jí gbé.</yor>"}
|
samples/flash/codeswitch_dynacc.mp3
ADDED
|
Binary file (75.9 kB). View file
|
|
|
samples/flash/codeswitch_ibo_pcm_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:26d4ac3d1fcae8484641e547e455420f54dd987b9b1184624ef40de80c3d3d8a
|
| 3 |
+
size 175245
|
samples/flash/codeswitch_yor_eng.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3c09b28d483a2f7c740d9b05438767f2f457cb1bd2bd49029d31760a8a0fc7ad
|
| 3 |
+
size 104205
|
samples/flash/diacritics_yoruba_from_plain.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9ce4b97b0225a62356b2996e9d551ff74e2a2b16ca34b2707873095772995889
|
| 3 |
+
size 107085
|
samples/flash/hausa_male.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:21354db9f258956e861b5526289f2b49dc908d2760de89913a65af8e74ac95eb
|
| 3 |
+
size 208845
|
samples/flash/igbo_para_female.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c24da6ec6eaec6b332f1a9b0dac2eb944e08a13187e9c07dd5d1b0577ef8c0f5
|
| 3 |
+
size 245805
|
samples/flash/igbo_pure_female.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:39abdd290724dcc05cd7d5f928cde2f178044115b26795bf16da48963cfe2ff9
|
| 3 |
+
size 164205
|
samples/flash/numbers_igbo.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:daa1ea59e60f9c1b3fefde255ce5c98ec16513d64fef2aebbd1f035ae0227283
|
| 3 |
+
size 262605
|
samples/flash/pidgin_female.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:255ae0e9a883f93b5bc48c2eeedac3138bd7304ee01bfd675e9c29ff99957189
|
| 3 |
+
size 181005
|
samples/flash/yoruba_female.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:8c0011b2c16edbdd88e91511ce8d455e358dee285084a7bffc4f6211e6ec6888
|
| 3 |
+
size 162285
|
samples/flash/yoruba_male.mp3
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:550aa664f313b854594ebfd263b015224a1fce1a0abae2c8ce6215541121092f
|
| 3 |
+
size 181005
|
settings.json
CHANGED
|
@@ -1,7 +1,20 @@
|
|
| 1 |
{
|
| 2 |
-
"default_version": "
|
| 3 |
"default_voice": "anchor_male",
|
| 4 |
"versions": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"phase2": {
|
| 6 |
"lm": "checkpoints/phase2/p2_lm_B/best.pt",
|
| 7 |
"flow": "checkpoints/phase2/p2_flow_sft/best.pt",
|
|
@@ -27,6 +40,11 @@
|
|
| 27 |
"waxal_yor_5_female"
|
| 28 |
],
|
| 29 |
"recommended": {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
"phase3": [
|
| 31 |
"waxal_ibo_5_female",
|
| 32 |
"waxal_yor_5_female"
|
|
@@ -34,7 +52,7 @@
|
|
| 34 |
"phase2": [
|
| 35 |
"anchor_male"
|
| 36 |
],
|
| 37 |
-
"note": "
|
| 38 |
},
|
| 39 |
"rates": [
|
| 40 |
"none",
|
|
|
|
| 1 |
{
|
| 2 |
+
"default_version": "flash",
|
| 3 |
"default_voice": "anchor_male",
|
| 4 |
"versions": {
|
| 5 |
+
"flash": {
|
| 6 |
+
"engine": "cosyvoice3",
|
| 7 |
+
"base": "FunAudioLLM/Fun-CosyVoice3-0.5B-2512",
|
| 8 |
+
"lm": "checkpoints/flash/flash_dpo/best.pt",
|
| 9 |
+
"diacritics": "checkpoints/flash/diacritics_byt5",
|
| 10 |
+
"sampler": "silexcap",
|
| 11 |
+
"one_pass": true,
|
| 12 |
+
"postprocess": false,
|
| 13 |
+
"rate": "normal",
|
| 14 |
+
"frontend": "codeswitch",
|
| 15 |
+
"translate": "experimental, off by default (--frontend translate --experimental_translate)",
|
| 16 |
+
"desc": "Flash (default): Flash-DPO LM on Fun-CosyVoice3-0.5B-2512 (SFT on licensed data + DPO with a naturalness/CER/pace/pause reward), CV3 flow+vocoder zero-shot from the voice clip; text front-end restores Yoruba/Igbo diacritics; one pass per paragraph, model pauses, no post-processing"
|
| 17 |
+
},
|
| 18 |
"phase2": {
|
| 19 |
"lm": "checkpoints/phase2/p2_lm_B/best.pt",
|
| 20 |
"flow": "checkpoints/phase2/p2_flow_sft/best.pt",
|
|
|
|
| 40 |
"waxal_yor_5_female"
|
| 41 |
],
|
| 42 |
"recommended": {
|
| 43 |
+
"flash": [
|
| 44 |
+
"anchor_male",
|
| 45 |
+
"waxal_ibo_5_female",
|
| 46 |
+
"waxal_yor_5_female"
|
| 47 |
+
],
|
| 48 |
"phase3": [
|
| 49 |
"waxal_ibo_5_female",
|
| 50 |
"waxal_yor_5_female"
|
|
|
|
| 52 |
"phase2": [
|
| 53 |
"anchor_male"
|
| 54 |
],
|
| 55 |
+
"note": "Flash is the default and the best-scoring version for every voice (clipped endings anchor 9.1%->7.1%, female Igbo 22.8%->10.7%; pace ~native). Known weakness: with anchor_male, Flash under-pauses in Igbo and Yoruba. Earlier listening verdict (2026-10-21): Phase 3 with the female voices, Phase 2 with the male anchor. Use --compare to A/B before use."
|
| 56 |
},
|
| 57 |
"rates": [
|
| 58 |
"none",
|