v1 delay-pattern (k=8): replace flat k=3 with MusicGen-style delay
Browse files- README.md +77 -64
- added_tokens.json +3 -4
- config.json +5 -5
- configuration_wren.py +7 -8
- model.safetensors +2 -2
- modeling_wren.py +93 -56
- processing_wren.py +9 -10
- special_tokens_map.json +3 -10
- tokenizer.json +3 -12
- tokenizer_config.json +5 -14
README.md
CHANGED
|
@@ -14,52 +14,62 @@ tags:
|
|
| 14 |
- neural-codec
|
| 15 |
pipeline_tag: text-to-speech
|
| 16 |
datasets:
|
| 17 |
-
-
|
|
|
|
| 18 |
---
|
| 19 |
|
| 20 |
# Wren-TTS-360M (v1)
|
| 21 |
|
| 22 |
**Wren** is a series of small (<3B) multimodal speech LLMs covering TTS, ASR, and
|
| 23 |
-
speech-language modelling.
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
|
| 28 |
-
An
|
| 29 |
|
| 30 |
## Architecture
|
| 31 |
|
| 32 |
```
|
| 33 |
-
text ──► SmolLM2-360M ──► k
|
| 34 |
```
|
| 35 |
|
| 36 |
-
- **Backbone:** SmolLM2-360M (causal LM
|
| 37 |
- **Audio tokenizer:** Mimi (`kyutai/mimi`), 12.5 fps, 2048-entry codebooks
|
| 38 |
-
- **Codebooks used:**
|
| 39 |
-
- **
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
- **
|
| 43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
|
| 45 |
## Training data
|
| 46 |
|
| 47 |
-
- [
|
| 48 |
-
-
|
|
|
|
| 49 |
|
| 50 |
-
Text
|
| 51 |
-
only; LJSpeech was not included in this run.
|
| 52 |
|
| 53 |
## Usage
|
| 54 |
|
| 55 |
```bash
|
| 56 |
-
pip install torch torchaudio transformers
|
| 57 |
```
|
| 58 |
|
| 59 |
-
|
|
|
|
| 60 |
|
| 61 |
```python
|
| 62 |
import torch
|
|
|
|
|
|
|
| 63 |
from transformers import AutoModel, AutoProcessor
|
| 64 |
|
| 65 |
model_id = "shangeth/Wren-TTS-360M-v1"
|
|
@@ -68,74 +78,75 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
|
|
| 68 |
processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
|
| 69 |
model = AutoModel.from_pretrained(model_id, trust_remote_code=True).to(device).eval()
|
| 70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 71 |
inputs = processor("Hello world, how are you today?")
|
| 72 |
inputs = {k: v.to(device) for k, v in inputs.items()}
|
| 73 |
|
| 74 |
waveform = model.generate(
|
| 75 |
**inputs,
|
|
|
|
| 76 |
max_audio_frames=200,
|
| 77 |
min_audio_frames=2,
|
| 78 |
-
temperature=0.8,
|
| 79 |
-
top_k=50,
|
| 80 |
-
top_p=0.9,
|
| 81 |
output_audio=True,
|
| 82 |
)
|
| 83 |
processor.save_audio(waveform, "out.wav")
|
| 84 |
```
|
| 85 |
|
| 86 |
-
##
|
| 87 |
-
|
| 88 |
-
```python
|
| 89 |
-
import torchaudio
|
| 90 |
|
| 91 |
-
|
| 92 |
-
|
| 93 |
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
max_audio_frames=200,
|
| 99 |
-
min_audio_frames=2,
|
| 100 |
-
temperature=0.8, top_k=50, top_p=0.9,
|
| 101 |
-
)
|
| 102 |
-
processor.save_audio(waveform, "cloned.wav")
|
| 103 |
-
```
|
| 104 |
|
| 105 |
-
##
|
| 106 |
|
| 107 |
-
|
| 108 |
-
|
|
|
|
| 109 |
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
|
|
|
|
|
|
| 114 |
|
| 115 |
## Limitations & known issues
|
| 116 |
|
| 117 |
-
- **Hallucinated continuations
|
| 118 |
-
|
| 119 |
-
(one EOS target per ~100–300 audio frames) and is being addressed in training.
|
| 120 |
- **English only.**
|
| 121 |
-
- **
|
| 122 |
-
|
| 123 |
-
- **
|
| 124 |
-
|
|
|
|
| 125 |
|
| 126 |
## The Wren series
|
| 127 |
|
| 128 |
-
Wren is a family of compact (<3B parameter) multimodal speech LLMs — small enough
|
| 129 |
-
on a single consumer GPU, designed for open research on unified speech
|
| 130 |
-
synthesis. Planned siblings:
|
| 131 |
|
| 132 |
- **Wren-TTS** — text → speech (this release)
|
| 133 |
- **Wren-ASR** — speech → text
|
| 134 |
- **Wren-LM** — speech-language modelling / dialog
|
| 135 |
- **Wren-Omni** — unified ASR + TTS + LM in one checkpoint
|
| 136 |
|
| 137 |
-
All Wren models share the same design principles: small backbone LLM + neural
|
| 138 |
-
open weights, simple PyTorch checkpoints, reproducible training recipes.
|
| 139 |
|
| 140 |
## Repository contents
|
| 141 |
|
|
@@ -143,7 +154,7 @@ open weights, simple PyTorch checkpoints, reproducible training recipes.
|
|
| 143 |
|---|---|
|
| 144 |
| `model.safetensors` | Model weights |
|
| 145 |
| `config.json` | `WrenConfig` (with `auto_map` for `trust_remote_code`) |
|
| 146 |
-
| `tokenizer.json` + friends | SmolLM2 tokenizer with Wren's
|
| 147 |
| `processor_config.json` | `WrenProcessor` auto_map |
|
| 148 |
| `configuration_wren.py` | `WrenConfig(PretrainedConfig)` |
|
| 149 |
| `modeling_wren.py` | `WrenForTTS(PreTrainedModel)` — loads Mimi codec lazily on first generate |
|
|
@@ -160,11 +171,13 @@ open weights, simple PyTorch checkpoints, reproducible training recipes.
|
|
| 160 |
url = {https://github.com/shangeth/wren}
|
| 161 |
}
|
| 162 |
|
| 163 |
-
@inproceedings{
|
| 164 |
-
title = {
|
| 165 |
-
author = {
|
| 166 |
-
|
| 167 |
-
|
|
|
|
|
|
|
| 168 |
}
|
| 169 |
```
|
| 170 |
|
|
|
|
| 14 |
- neural-codec
|
| 15 |
pipeline_tag: text-to-speech
|
| 16 |
datasets:
|
| 17 |
+
- mythicinfinity/libritts_r
|
| 18 |
+
- keithito/lj_speech
|
| 19 |
---
|
| 20 |
|
| 21 |
# Wren-TTS-360M (v1)
|
| 22 |
|
| 23 |
**Wren** is a series of small (<3B) multimodal speech LLMs covering TTS, ASR, and
|
| 24 |
+
speech-language modelling. **Wren-TTS-360M-v1** generates
|
| 25 |
+
[Kyutai Mimi](https://huggingface.co/kyutai/mimi) neural-codec tokens from text
|
| 26 |
+
using a [HuggingFaceTB/SmolLM2-360M](https://huggingface.co/HuggingFaceTB/SmolLM2-360M)
|
| 27 |
+
backbone, then decodes to 24 kHz waveform with the Mimi decoder.
|
| 28 |
|
| 29 |
+
An open research checkpoint — useful for experimentation, not production.
|
| 30 |
|
| 31 |
## Architecture
|
| 32 |
|
| 33 |
```
|
| 34 |
+
text ──► SmolLM2-360M ──► k=8 parallel Mimi heads ──► Mimi decoder ──► 24 kHz
|
| 35 |
```
|
| 36 |
|
| 37 |
+
- **Backbone:** SmolLM2-360M (causal LM; text + audio share the same backbone)
|
| 38 |
- **Audio tokenizer:** Mimi (`kyutai/mimi`), 12.5 fps, 2048-entry codebooks
|
| 39 |
+
- **Codebooks used:** all 8 Mimi codebooks
|
| 40 |
+
- **Layout:** **MusicGen-style delay pattern** — at each step, k summed codebook
|
| 41 |
+
embeddings go in, k parallel heads predict k tokens out. Codebook q at frame f
|
| 42 |
+
lives at step `s = f + q`, so same-frame RVQ conditioning is preserved via the delay.
|
| 43 |
+
- **Per-codebook input tables:** `Embedding(2049, hidden)` — extra row = `AUDIO_PAD` at
|
| 44 |
+
sequence edges.
|
| 45 |
+
- **Per-codebook output heads:** `Linear(hidden, 2048)` for cb1..cb7.
|
| 46 |
+
cb0 gets `Linear(hidden, 2049)` with the extra class = `AUDIO_EOS` (stop token).
|
| 47 |
+
- **Speaker conditioning (required):** prepend `<|reference_start|> ref_codes <|reference_end|>`
|
| 48 |
+
to the prompt; `ref_codes` is the Mimi encoding of a short reference clip. The model was
|
| 49 |
+
trained multispeaker-only and expects a reference at inference — without one, output quality
|
| 50 |
+
is poor.
|
| 51 |
|
| 52 |
## Training data
|
| 53 |
|
| 54 |
+
- [LibriTTS-R](https://huggingface.co/datasets/mythicinfinity/libritts_r)
|
| 55 |
+
`train-clean-{100,360}` + `train-other-500` — ~960 h multi-speaker English
|
| 56 |
+
- [LJSpeech](https://keithito.com/LJ-Speech-Dataset/) — ~24 h single speaker
|
| 57 |
|
| 58 |
+
Text casing and punctuation are preserved. Pass text naturally — do not pre-lowercase.
|
|
|
|
| 59 |
|
| 60 |
## Usage
|
| 61 |
|
| 62 |
```bash
|
| 63 |
+
pip install torch torchaudio transformers datasets
|
| 64 |
```
|
| 65 |
|
| 66 |
+
> **A reference audio clip is required.** The model was trained multispeaker-only; without
|
| 67 |
+
> `ref_codes` it produces poor output. Any 3–12 s English speech clip works as the voice reference.
|
| 68 |
|
| 69 |
```python
|
| 70 |
import torch
|
| 71 |
+
import numpy as np
|
| 72 |
+
from datasets import load_dataset
|
| 73 |
from transformers import AutoModel, AutoProcessor
|
| 74 |
|
| 75 |
model_id = "shangeth/Wren-TTS-360M-v1"
|
|
|
|
| 78 |
processor = AutoProcessor.from_pretrained(model_id, trust_remote_code=True)
|
| 79 |
model = AutoModel.from_pretrained(model_id, trust_remote_code=True).to(device).eval()
|
| 80 |
|
| 81 |
+
# Grab one LibriSpeech test-clean clip (~3.5s, not in training) as the reference voice.
|
| 82 |
+
# Swap this block for `torchaudio.load("your_reference.wav")` to use your own clip.
|
| 83 |
+
sample = next(iter(load_dataset("openslr/librispeech_asr", "clean", split="test", streaming=True)))
|
| 84 |
+
ref_wav = torch.from_numpy(np.asarray(sample["audio"]["array"], dtype=np.float32)).unsqueeze(0)
|
| 85 |
+
ref_sr = sample["audio"]["sampling_rate"]
|
| 86 |
+
ref_codes = model.encode_audio(ref_wav, ref_sr)[:, :150] # cap at ~12s; encode_audio resamples to 24 kHz
|
| 87 |
+
|
| 88 |
+
# Tokenize the target text and generate speech in the reference voice
|
| 89 |
inputs = processor("Hello world, how are you today?")
|
| 90 |
inputs = {k: v.to(device) for k, v in inputs.items()}
|
| 91 |
|
| 92 |
waveform = model.generate(
|
| 93 |
**inputs,
|
| 94 |
+
ref_codes=ref_codes,
|
| 95 |
max_audio_frames=200,
|
| 96 |
min_audio_frames=2,
|
| 97 |
+
temperature=0.8, top_k=50, top_p=0.9,
|
|
|
|
|
|
|
| 98 |
output_audio=True,
|
| 99 |
)
|
| 100 |
processor.save_audio(waveform, "out.wav")
|
| 101 |
```
|
| 102 |
|
| 103 |
+
## Sampling tips
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
+
Defaults: `temperature=0.8`, `top_k=50`, `top_p=0.9`, `max_audio_frames=200` (~16 s).
|
| 106 |
+
If you hear the model generating extra speech past the intended text (hallucination):
|
| 107 |
|
| 108 |
+
- Raise `eos_bias` — e.g. 2.0–6.0 — to make the model more eager to stop
|
| 109 |
+
- Lower `temperature` (0.6) and `top_p` (0.8)
|
| 110 |
+
- Set `max_audio_frames` ≈ `12 * len(text_in_chars)`
|
| 111 |
+
- Set `min_audio_frames=1` for very short prompts
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
|
| 113 |
+
## Why delay pattern
|
| 114 |
|
| 115 |
+
Mimi uses **residual vector quantization (RVQ)**: cb0 is semantic, cb1..cb7 encode
|
| 116 |
+
successive residuals. cb_q is only meaningful given cb0..cb_{q-1}, so same-frame
|
| 117 |
+
conditioning matters.
|
| 118 |
|
| 119 |
+
A flat interleaved layout (`cb0_f0, cb1_f0, ..., cb0_f1, ...`) preserves that
|
| 120 |
+
conditioning best but balloons sequence length by `k×` and forces `k` autoregressive
|
| 121 |
+
LLM calls per frame. The delay pattern keeps RVQ conditioning (cb_q at frame f is
|
| 122 |
+
predicted from a hidden state that has already attended over cb0..cb_{q-1} of the
|
| 123 |
+
same frame) while cutting sequence length to `T + k - 1` and LLM calls to **one per
|
| 124 |
+
step** — enabling all 8 Mimi codebooks without blowing up context.
|
| 125 |
|
| 126 |
## Limitations & known issues
|
| 127 |
|
| 128 |
+
- **Hallucinated continuations**: occasionally generates plausible speech past the
|
| 129 |
+
input text. Mitigate with `eos_bias` at inference.
|
|
|
|
| 130 |
- **English only.**
|
| 131 |
+
- **Audiobook-style prosody** inherited from LibriTTS-R; not as expressive as modern
|
| 132 |
+
conversational TTS.
|
| 133 |
+
- **Small backbone (360M)** — quality is below frontier TTS systems.
|
| 134 |
+
- cb0 begins to overfit earlier than cb3–cb7; the released checkpoint is the
|
| 135 |
+
best-epoch point (by overall val loss) from the full training run.
|
| 136 |
|
| 137 |
## The Wren series
|
| 138 |
|
| 139 |
+
Wren is a family of compact (<3B parameter) multimodal speech LLMs — small enough
|
| 140 |
+
to run on a single consumer GPU, designed for open research on unified speech
|
| 141 |
+
understanding and synthesis. Planned siblings:
|
| 142 |
|
| 143 |
- **Wren-TTS** — text → speech (this release)
|
| 144 |
- **Wren-ASR** — speech → text
|
| 145 |
- **Wren-LM** — speech-language modelling / dialog
|
| 146 |
- **Wren-Omni** — unified ASR + TTS + LM in one checkpoint
|
| 147 |
|
| 148 |
+
All Wren models share the same design principles: small backbone LLM + neural
|
| 149 |
+
audio codec, open weights, simple PyTorch checkpoints, reproducible training recipes.
|
| 150 |
|
| 151 |
## Repository contents
|
| 152 |
|
|
|
|
| 154 |
|---|---|
|
| 155 |
| `model.safetensors` | Model weights |
|
| 156 |
| `config.json` | `WrenConfig` (with `auto_map` for `trust_remote_code`) |
|
| 157 |
+
| `tokenizer.json` + friends | SmolLM2 tokenizer with Wren's 3 special tokens added |
|
| 158 |
| `processor_config.json` | `WrenProcessor` auto_map |
|
| 159 |
| `configuration_wren.py` | `WrenConfig(PretrainedConfig)` |
|
| 160 |
| `modeling_wren.py` | `WrenForTTS(PreTrainedModel)` — loads Mimi codec lazily on first generate |
|
|
|
|
| 171 |
url = {https://github.com/shangeth/wren}
|
| 172 |
}
|
| 173 |
|
| 174 |
+
@inproceedings{koizumi2023libritts,
|
| 175 |
+
title = {LibriTTS-R: A Restored Multi-Speaker Text-to-Speech Corpus},
|
| 176 |
+
author = {Koizumi, Yuma and Zen, Heiga and Karita, Shigeki and Ding, Yifan
|
| 177 |
+
and Yatabe, Kohei and Morioka, Nobuyuki and Bacchiani, Michiel and
|
| 178 |
+
Zhang, Yu and Han, Wei and Bapna, Ankur},
|
| 179 |
+
booktitle = {Interspeech},
|
| 180 |
+
year = {2023}
|
| 181 |
}
|
| 182 |
```
|
| 183 |
|
added_tokens.json
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
{
|
| 2 |
-
"<|
|
| 3 |
-
"<|
|
| 4 |
-
"<|
|
| 5 |
-
"<|audio_start|>": 49154
|
| 6 |
}
|
|
|
|
| 1 |
{
|
| 2 |
+
"<|audio_start|>": 49152,
|
| 3 |
+
"<|reference_end|>": 49154,
|
| 4 |
+
"<|reference_start|>": 49153
|
|
|
|
| 5 |
}
|
config.json
CHANGED
|
@@ -2,20 +2,20 @@
|
|
| 2 |
"architectures": [
|
| 3 |
"WrenForTTS"
|
| 4 |
],
|
| 5 |
-
"
|
| 6 |
-
"audio_eos_token_id": 49153,
|
| 7 |
-
"audio_sep_id": 49152,
|
| 8 |
-
"audio_start_id": 49154,
|
| 9 |
"auto_map": {
|
| 10 |
"AutoConfig": "configuration_wren.WrenConfig",
|
| 11 |
"AutoModel": "modeling_wren.WrenForTTS"
|
| 12 |
},
|
| 13 |
"codebook_size": 2048,
|
| 14 |
"dtype": "bfloat16",
|
| 15 |
-
"k_codebooks":
|
| 16 |
"llm_name": "HuggingFaceTB/SmolLM2-360M",
|
| 17 |
"mimi_model_name": "kyutai/mimi",
|
| 18 |
"model_type": "wren",
|
|
|
|
|
|
|
|
|
|
| 19 |
"sampling_rate": 24000,
|
| 20 |
"transformers_version": "4.57.6",
|
| 21 |
"vocab_size": 49160
|
|
|
|
| 2 |
"architectures": [
|
| 3 |
"WrenForTTS"
|
| 4 |
],
|
| 5 |
+
"audio_start_id": 49152,
|
|
|
|
|
|
|
|
|
|
| 6 |
"auto_map": {
|
| 7 |
"AutoConfig": "configuration_wren.WrenConfig",
|
| 8 |
"AutoModel": "modeling_wren.WrenForTTS"
|
| 9 |
},
|
| 10 |
"codebook_size": 2048,
|
| 11 |
"dtype": "bfloat16",
|
| 12 |
+
"k_codebooks": 8,
|
| 13 |
"llm_name": "HuggingFaceTB/SmolLM2-360M",
|
| 14 |
"mimi_model_name": "kyutai/mimi",
|
| 15 |
"model_type": "wren",
|
| 16 |
+
"pattern": "delay",
|
| 17 |
+
"reference_end_id": 49154,
|
| 18 |
+
"reference_start_id": 49153,
|
| 19 |
"sampling_rate": 24000,
|
| 20 |
"transformers_version": "4.57.6",
|
| 21 |
"vocab_size": 49160
|
configuration_wren.py
CHANGED
|
@@ -9,13 +9,13 @@ class WrenConfig(PretrainedConfig):
|
|
| 9 |
self,
|
| 10 |
llm_name: str = "HuggingFaceTB/SmolLM2-360M",
|
| 11 |
mimi_model_name: str = "kyutai/mimi",
|
| 12 |
-
k_codebooks: int =
|
| 13 |
codebook_size: int = 2048,
|
| 14 |
vocab_size: int = 49160,
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
sampling_rate: int = 24000,
|
| 20 |
**kwargs,
|
| 21 |
):
|
|
@@ -24,9 +24,8 @@ class WrenConfig(PretrainedConfig):
|
|
| 24 |
self.k_codebooks = k_codebooks
|
| 25 |
self.codebook_size = codebook_size
|
| 26 |
self.vocab_size = vocab_size
|
| 27 |
-
self.audio_sep_id = audio_sep_id
|
| 28 |
-
self.audio_eos_token_id = audio_eos_token_id
|
| 29 |
self.audio_start_id = audio_start_id
|
| 30 |
-
self.
|
|
|
|
| 31 |
self.sampling_rate = sampling_rate
|
| 32 |
super().__init__(**kwargs)
|
|
|
|
| 9 |
self,
|
| 10 |
llm_name: str = "HuggingFaceTB/SmolLM2-360M",
|
| 11 |
mimi_model_name: str = "kyutai/mimi",
|
| 12 |
+
k_codebooks: int = 8,
|
| 13 |
codebook_size: int = 2048,
|
| 14 |
vocab_size: int = 49160,
|
| 15 |
+
# Special-token IDs (tokenized positions in the text vocab)
|
| 16 |
+
audio_start_id: int = None, # <|audio_start|> — text→target-audio boundary
|
| 17 |
+
reference_start_id: int = None, # <|reference_start|> — opens speaker-reference block
|
| 18 |
+
reference_end_id: int = None, # <|reference_end|> — closes speaker-reference block
|
| 19 |
sampling_rate: int = 24000,
|
| 20 |
**kwargs,
|
| 21 |
):
|
|
|
|
| 24 |
self.k_codebooks = k_codebooks
|
| 25 |
self.codebook_size = codebook_size
|
| 26 |
self.vocab_size = vocab_size
|
|
|
|
|
|
|
| 27 |
self.audio_start_id = audio_start_id
|
| 28 |
+
self.reference_start_id = reference_start_id
|
| 29 |
+
self.reference_end_id = reference_end_id
|
| 30 |
self.sampling_rate = sampling_rate
|
| 31 |
super().__init__(**kwargs)
|
model.safetensors
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:df687c893d29e93e454908d8a158cb16991e487dbdec86ecf94cccbe4ef37913
|
| 3 |
+
size 849556624
|
modeling_wren.py
CHANGED
|
@@ -3,8 +3,19 @@ Wren-TTS model — a transformers-compatible wrapper over SmolLM2 + Mimi codeboo
|
|
| 3 |
|
| 4 |
Designed for use with `AutoModel.from_pretrained(..., trust_remote_code=True)`.
|
| 5 |
Self-contained: no imports from a `src/` folder.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
"""
|
| 7 |
|
|
|
|
| 8 |
from typing import Optional
|
| 9 |
|
| 10 |
import torch
|
|
@@ -18,15 +29,6 @@ except ImportError:
|
|
| 18 |
|
| 19 |
|
| 20 |
class WrenForTTS(PreTrainedModel):
|
| 21 |
-
"""
|
| 22 |
-
SmolLM2 backbone + k separate audio-code embedding tables + k audio heads.
|
| 23 |
-
|
| 24 |
-
Sequence layout fed to the LLM (via inputs_embeds):
|
| 25 |
-
[ text tokens... | <audio_sep> | cb0_f0 | cb1_f0 | ... | cbk_f0 | cb0_f1 | ... ]
|
| 26 |
-
|
| 27 |
-
cb0's head has an extra output class `AUDIO_EOS = codebook_size` used as stop token.
|
| 28 |
-
"""
|
| 29 |
-
|
| 30 |
config_class = WrenConfig
|
| 31 |
base_model_prefix = "wren"
|
| 32 |
|
|
@@ -34,18 +36,21 @@ class WrenForTTS(PreTrainedModel):
|
|
| 34 |
super().__init__(config)
|
| 35 |
self.k = config.k_codebooks
|
| 36 |
self.AUDIO_EOS = config.codebook_size
|
|
|
|
| 37 |
|
| 38 |
# Build backbone from its config only. Pretrained weights for the backbone
|
| 39 |
# are included in our own state_dict, so no need to re-download here.
|
| 40 |
-
# Set vocab_size directly on the sub-config to avoid a subsequent
|
| 41 |
-
# resize_token_embeddings call (which breaks under meta-tensor init).
|
| 42 |
llm_cfg = AutoConfig.from_pretrained(config.llm_name)
|
| 43 |
llm_cfg.vocab_size = config.vocab_size
|
| 44 |
self.llm = AutoModelForCausalLM.from_config(llm_cfg)
|
| 45 |
|
| 46 |
hidden = self.llm.config.hidden_size
|
|
|
|
|
|
|
|
|
|
|
|
|
| 47 |
self.audio_embeds = nn.ModuleList([
|
| 48 |
-
nn.Embedding(config.codebook_size, hidden)
|
| 49 |
for _ in range(self.k)
|
| 50 |
])
|
| 51 |
self.audio_heads = nn.ModuleList([
|
|
@@ -53,6 +58,7 @@ class WrenForTTS(PreTrainedModel):
|
|
| 53 |
for i in range(self.k)
|
| 54 |
])
|
| 55 |
|
|
|
|
| 56 |
self._mimi = None # lazy-loaded on first use
|
| 57 |
|
| 58 |
# --- Mimi codec (lazy-loaded, decoder + encoder used for audio I/O) ---
|
|
@@ -94,6 +100,13 @@ class WrenForTTS(PreTrainedModel):
|
|
| 94 |
|
| 95 |
# --- Generation ---
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
@torch.no_grad()
|
| 98 |
def generate(
|
| 99 |
self,
|
|
@@ -112,11 +125,11 @@ class WrenForTTS(PreTrainedModel):
|
|
| 112 |
Generate Mimi codes (or waveform) from a tokenized prompt.
|
| 113 |
|
| 114 |
Args:
|
| 115 |
-
input_ids: [1, L] — text tokens ending with <|
|
| 116 |
ref_codes: optional [k, T_ref] reference codes for voice cloning.
|
| 117 |
max_audio_frames: hard cap on output length.
|
| 118 |
-
min_audio_frames: suppress EOS for this many frames
|
| 119 |
-
eos_bias: additive bias on AUDIO_EOS logit; raise (
|
| 120 |
output_audio: if True, return [1, T] waveform; else return [k, n_frames] codes.
|
| 121 |
"""
|
| 122 |
device = next(self.parameters()).device
|
|
@@ -128,67 +141,91 @@ class WrenForTTS(PreTrainedModel):
|
|
| 128 |
|
| 129 |
prompt_embeds_list = []
|
| 130 |
|
| 131 |
-
# Optional reference
|
| 132 |
if ref_codes is not None:
|
| 133 |
-
if self.config.
|
| 134 |
-
raise ValueError("
|
| 135 |
ref_codes = ref_codes.to(device)
|
| 136 |
-
|
|
|
|
| 137 |
prompt_embeds_list.append(embed_tokens(start_t.clamp(0, text_vocab - 1)))
|
| 138 |
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
|
| 145 |
-
end_t = torch.tensor([[self.config.
|
| 146 |
prompt_embeds_list.append(embed_tokens(end_t.clamp(0, text_vocab - 1)))
|
| 147 |
|
| 148 |
-
# Text prompt — already terminated by <|
|
| 149 |
ids = input_ids.to(device)
|
| 150 |
if ids.dim() == 1:
|
| 151 |
ids = ids.unsqueeze(0)
|
| 152 |
prompt_embeds_list.append(embed_tokens(ids.clamp(0, text_vocab - 1)))
|
| 153 |
|
| 154 |
prompt_embeds = torch.cat(prompt_embeds_list, dim=1).to(llm_dtype)
|
| 155 |
-
out
|
| 156 |
-
hidden
|
| 157 |
-
past_kv
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
break
|
| 174 |
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
if audio_pos % self.k == 0:
|
| 178 |
-
n_frames += 1
|
| 179 |
-
|
| 180 |
-
embed_idx = next_code.clamp(0, self.config.codebook_size - 1)
|
| 181 |
-
emb = self.audio_embeds[cb_idx](embed_idx.unsqueeze(0)).to(hidden.dtype)
|
| 182 |
-
out = self.llm.model(inputs_embeds=emb, past_key_values=past_kv, use_cache=True)
|
| 183 |
hidden = out.last_hidden_state
|
| 184 |
past_kv = out.past_key_values
|
| 185 |
|
| 186 |
-
|
| 187 |
-
if
|
|
|
|
|
|
|
|
|
|
| 188 |
codes = torch.zeros(self.k, 0, dtype=torch.long)
|
| 189 |
else:
|
| 190 |
-
codes = torch.
|
| 191 |
-
|
|
|
|
| 192 |
|
| 193 |
if output_audio:
|
| 194 |
return self.decode_audio(codes)
|
|
|
|
| 3 |
|
| 4 |
Designed for use with `AutoModel.from_pretrained(..., trust_remote_code=True)`.
|
| 5 |
Self-contained: no imports from a `src/` folder.
|
| 6 |
+
|
| 7 |
+
Sequence layout (MusicGen-style delay pattern):
|
| 8 |
+
|
| 9 |
+
[ text tokens... | <audio_start> | tgt_delay_steps ]
|
| 10 |
+
+ optional [ <reference_start> | ref_delay_steps | <reference_end> ] prefix
|
| 11 |
+
|
| 12 |
+
At each audio step s the model sees the sum of k per-codebook input embeddings
|
| 13 |
+
(scaled by 1/sqrt(k)) and predicts k tokens via k parallel heads. Codebook q at
|
| 14 |
+
frame f lives at step s = f + q. AUDIO_EOS (=codebook_size) is cb0's stop class;
|
| 15 |
+
cb0 emits it at step T (one past the last real frame).
|
| 16 |
"""
|
| 17 |
|
| 18 |
+
import math
|
| 19 |
from typing import Optional
|
| 20 |
|
| 21 |
import torch
|
|
|
|
| 29 |
|
| 30 |
|
| 31 |
class WrenForTTS(PreTrainedModel):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 32 |
config_class = WrenConfig
|
| 33 |
base_model_prefix = "wren"
|
| 34 |
|
|
|
|
| 36 |
super().__init__(config)
|
| 37 |
self.k = config.k_codebooks
|
| 38 |
self.AUDIO_EOS = config.codebook_size
|
| 39 |
+
self.AUDIO_PAD = config.codebook_size
|
| 40 |
|
| 41 |
# Build backbone from its config only. Pretrained weights for the backbone
|
| 42 |
# are included in our own state_dict, so no need to re-download here.
|
|
|
|
|
|
|
| 43 |
llm_cfg = AutoConfig.from_pretrained(config.llm_name)
|
| 44 |
llm_cfg.vocab_size = config.vocab_size
|
| 45 |
self.llm = AutoModelForCausalLM.from_config(llm_cfg)
|
| 46 |
|
| 47 |
hidden = self.llm.config.hidden_size
|
| 48 |
+
|
| 49 |
+
# Input tables: codebook_size + 1 (extra row at index codebook_size = AUDIO_PAD).
|
| 50 |
+
# Output heads: cb0 has codebook_size + 1 (extra class = AUDIO_EOS); cb1..cb_{k-1}
|
| 51 |
+
# have codebook_size (no PAD/EOS output — PAD positions have -100 labels in training).
|
| 52 |
self.audio_embeds = nn.ModuleList([
|
| 53 |
+
nn.Embedding(config.codebook_size + 1, hidden)
|
| 54 |
for _ in range(self.k)
|
| 55 |
])
|
| 56 |
self.audio_heads = nn.ModuleList([
|
|
|
|
| 58 |
for i in range(self.k)
|
| 59 |
])
|
| 60 |
|
| 61 |
+
self.embed_scale = 1.0 / math.sqrt(self.k)
|
| 62 |
self._mimi = None # lazy-loaded on first use
|
| 63 |
|
| 64 |
# --- Mimi codec (lazy-loaded, decoder + encoder used for audio I/O) ---
|
|
|
|
| 100 |
|
| 101 |
# --- Generation ---
|
| 102 |
|
| 103 |
+
def _audio_embed_step(self, codes_step: torch.LongTensor) -> torch.Tensor:
|
| 104 |
+
"""Summed per-codebook embedding for one audio step. codes_step: [1, k]. Returns [1, 1, H]."""
|
| 105 |
+
acc = self.audio_embeds[0](codes_step[:, 0:1])
|
| 106 |
+
for q in range(1, self.k):
|
| 107 |
+
acc = acc + self.audio_embeds[q](codes_step[:, q:q + 1])
|
| 108 |
+
return acc * self.embed_scale
|
| 109 |
+
|
| 110 |
@torch.no_grad()
|
| 111 |
def generate(
|
| 112 |
self,
|
|
|
|
| 125 |
Generate Mimi codes (or waveform) from a tokenized prompt.
|
| 126 |
|
| 127 |
Args:
|
| 128 |
+
input_ids: [1, L] — text tokens ending with <|audio_start|>, as produced by WrenProcessor.
|
| 129 |
ref_codes: optional [k, T_ref] reference codes for voice cloning.
|
| 130 |
max_audio_frames: hard cap on output length.
|
| 131 |
+
min_audio_frames: suppress EOS for this many frames.
|
| 132 |
+
eos_bias: additive bias on cb0's AUDIO_EOS logit; raise (2–6) to reduce tail hallucination.
|
| 133 |
output_audio: if True, return [1, T] waveform; else return [k, n_frames] codes.
|
| 134 |
"""
|
| 135 |
device = next(self.parameters()).device
|
|
|
|
| 141 |
|
| 142 |
prompt_embeds_list = []
|
| 143 |
|
| 144 |
+
# Optional reference block: <reference_start> ref_delayed <reference_end>
|
| 145 |
if ref_codes is not None:
|
| 146 |
+
if self.config.reference_start_id is None or self.config.reference_end_id is None:
|
| 147 |
+
raise ValueError("reference_start_id/reference_end_id missing from config; cannot use ref_codes")
|
| 148 |
ref_codes = ref_codes.to(device)
|
| 149 |
+
|
| 150 |
+
start_t = torch.tensor([[self.config.reference_start_id]], dtype=torch.long, device=device)
|
| 151 |
prompt_embeds_list.append(embed_tokens(start_t.clamp(0, text_vocab - 1)))
|
| 152 |
|
| 153 |
+
T_ref = ref_codes.shape[1]
|
| 154 |
+
L_ref = T_ref + self.k - 1
|
| 155 |
+
ref_delayed = torch.full((self.k, L_ref), self.AUDIO_PAD, dtype=torch.long, device=device)
|
| 156 |
+
for q in range(self.k):
|
| 157 |
+
ref_delayed[q, q:q + T_ref] = ref_codes[q]
|
| 158 |
+
|
| 159 |
+
for s in range(L_ref):
|
| 160 |
+
codes_step = ref_delayed[:, s:s + 1].T.contiguous() # [1, k]
|
| 161 |
+
prompt_embeds_list.append(self._audio_embed_step(codes_step))
|
| 162 |
|
| 163 |
+
end_t = torch.tensor([[self.config.reference_end_id]], dtype=torch.long, device=device)
|
| 164 |
prompt_embeds_list.append(embed_tokens(end_t.clamp(0, text_vocab - 1)))
|
| 165 |
|
| 166 |
+
# Text prompt — already terminated by <|audio_start|> via the processor
|
| 167 |
ids = input_ids.to(device)
|
| 168 |
if ids.dim() == 1:
|
| 169 |
ids = ids.unsqueeze(0)
|
| 170 |
prompt_embeds_list.append(embed_tokens(ids.clamp(0, text_vocab - 1)))
|
| 171 |
|
| 172 |
prompt_embeds = torch.cat(prompt_embeds_list, dim=1).to(llm_dtype)
|
| 173 |
+
out = self.llm.model(inputs_embeds=prompt_embeds, use_cache=True)
|
| 174 |
+
hidden = out.last_hidden_state
|
| 175 |
+
past_kv = out.past_key_values
|
| 176 |
+
|
| 177 |
+
# Delay-pattern autoregressive loop
|
| 178 |
+
outputs: list = [[] for _ in range(self.k)]
|
| 179 |
+
eos_step: Optional[int] = None
|
| 180 |
+
max_steps = max_audio_frames + self.k - 1
|
| 181 |
+
|
| 182 |
+
for step in range(max_steps):
|
| 183 |
+
h = hidden[:, -1:, :]
|
| 184 |
+
logits_per_cb = [self.audio_heads[q](h.float()).squeeze(1) for q in range(self.k)]
|
| 185 |
+
|
| 186 |
+
logits_per_cb[0][:, self.AUDIO_EOS] = logits_per_cb[0][:, self.AUDIO_EOS] + eos_bias
|
| 187 |
+
if step < min_audio_frames:
|
| 188 |
+
logits_per_cb[0][:, self.AUDIO_EOS] = float("-inf")
|
| 189 |
+
|
| 190 |
+
next_codes = torch.empty(self.k, dtype=torch.long, device=device)
|
| 191 |
+
for q in range(self.k):
|
| 192 |
+
if step < q:
|
| 193 |
+
next_codes[q] = self.AUDIO_PAD
|
| 194 |
+
continue
|
| 195 |
+
if q == 0 and eos_step is not None:
|
| 196 |
+
next_codes[q] = self.AUDIO_PAD
|
| 197 |
+
continue
|
| 198 |
+
if q > 0 and eos_step is not None and (step - q) >= eos_step:
|
| 199 |
+
next_codes[q] = self.AUDIO_PAD
|
| 200 |
+
continue
|
| 201 |
+
sampled = _sample(logits_per_cb[q], temperature, top_k, top_p)
|
| 202 |
+
if q == 0 and sampled.item() == self.AUDIO_EOS:
|
| 203 |
+
eos_step = step
|
| 204 |
+
next_codes[q] = self.AUDIO_PAD
|
| 205 |
+
else:
|
| 206 |
+
next_codes[q] = sampled
|
| 207 |
+
|
| 208 |
+
for q in range(self.k):
|
| 209 |
+
outputs[q].append(next_codes[q].item())
|
| 210 |
+
|
| 211 |
+
if eos_step is not None and step >= eos_step + self.k - 1:
|
| 212 |
break
|
| 213 |
|
| 214 |
+
next_embed = self._audio_embed_step(next_codes.unsqueeze(0)).to(hidden.dtype)
|
| 215 |
+
out = self.llm.model(inputs_embeds=next_embed, past_key_values=past_kv, use_cache=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
hidden = out.last_hidden_state
|
| 217 |
past_kv = out.past_key_values
|
| 218 |
|
| 219 |
+
# Un-delay into [k, T]
|
| 220 |
+
T = eos_step if eos_step is not None else max_audio_frames
|
| 221 |
+
max_available = min(len(outputs[q]) - q for q in range(self.k))
|
| 222 |
+
T = min(T, max_available)
|
| 223 |
+
if T <= 0:
|
| 224 |
codes = torch.zeros(self.k, 0, dtype=torch.long)
|
| 225 |
else:
|
| 226 |
+
codes = torch.empty(self.k, T, dtype=torch.long)
|
| 227 |
+
for q in range(self.k):
|
| 228 |
+
codes[q] = torch.tensor(outputs[q][q:q + T], dtype=torch.long)
|
| 229 |
|
| 230 |
if output_audio:
|
| 231 |
return self.decode_audio(codes)
|
processing_wren.py
CHANGED
|
@@ -1,8 +1,10 @@
|
|
| 1 |
"""
|
| 2 |
Wren processor: text tokenization + audio saving.
|
| 3 |
|
| 4 |
-
Text is
|
| 5 |
-
|
|
|
|
|
|
|
| 6 |
"""
|
| 7 |
|
| 8 |
from typing import List, Union
|
|
@@ -17,9 +19,9 @@ class WrenProcessor(ProcessorMixin):
|
|
| 17 |
|
| 18 |
def __init__(self, tokenizer):
|
| 19 |
super().__init__(tokenizer=tokenizer)
|
| 20 |
-
self.
|
| 21 |
-
self.
|
| 22 |
-
self.
|
| 23 |
|
| 24 |
def __call__(
|
| 25 |
self,
|
|
@@ -27,9 +29,6 @@ class WrenProcessor(ProcessorMixin):
|
|
| 27 |
return_tensors: str = "pt",
|
| 28 |
**kwargs,
|
| 29 |
):
|
| 30 |
-
# Training data was lowercased; match that distribution.
|
| 31 |
-
text = text.lower() if isinstance(text, str) else [t.lower() for t in text]
|
| 32 |
-
|
| 33 |
enc = self.tokenizer(
|
| 34 |
text,
|
| 35 |
add_special_tokens = False,
|
|
@@ -40,10 +39,10 @@ class WrenProcessor(ProcessorMixin):
|
|
| 40 |
if ids.dim() == 1:
|
| 41 |
ids = ids.unsqueeze(0)
|
| 42 |
|
| 43 |
-
# Append <|
|
| 44 |
sep = torch.full(
|
| 45 |
(ids.shape[0], 1),
|
| 46 |
-
self.
|
| 47 |
dtype=ids.dtype,
|
| 48 |
device=ids.device,
|
| 49 |
)
|
|
|
|
| 1 |
"""
|
| 2 |
Wren processor: text tokenization + audio saving.
|
| 3 |
|
| 4 |
+
Text casing is preserved as-is. Pass text naturally ("Hello, World!") — the model
|
| 5 |
+
is trained on mixed-case data (LJSpeech mixed-case, LibriTTS with punctuation).
|
| 6 |
+
The `<|audio_start|>` separator is always appended so `model.generate(**processor(text))`
|
| 7 |
+
"just works".
|
| 8 |
"""
|
| 9 |
|
| 10 |
from typing import List, Union
|
|
|
|
| 19 |
|
| 20 |
def __init__(self, tokenizer):
|
| 21 |
super().__init__(tokenizer=tokenizer)
|
| 22 |
+
self.audio_start_id = tokenizer.convert_tokens_to_ids("<|audio_start|>")
|
| 23 |
+
self.reference_start_id = tokenizer.convert_tokens_to_ids("<|reference_start|>")
|
| 24 |
+
self.reference_end_id = tokenizer.convert_tokens_to_ids("<|reference_end|>")
|
| 25 |
|
| 26 |
def __call__(
|
| 27 |
self,
|
|
|
|
| 29 |
return_tensors: str = "pt",
|
| 30 |
**kwargs,
|
| 31 |
):
|
|
|
|
|
|
|
|
|
|
| 32 |
enc = self.tokenizer(
|
| 33 |
text,
|
| 34 |
add_special_tokens = False,
|
|
|
|
| 39 |
if ids.dim() == 1:
|
| 40 |
ids = ids.unsqueeze(0)
|
| 41 |
|
| 42 |
+
# Append <|audio_start|> as the final prompt token
|
| 43 |
sep = torch.full(
|
| 44 |
(ids.shape[0], 1),
|
| 45 |
+
self.audio_start_id,
|
| 46 |
dtype=ids.dtype,
|
| 47 |
device=ids.device,
|
| 48 |
)
|
special_tokens_map.json
CHANGED
|
@@ -1,28 +1,21 @@
|
|
| 1 |
{
|
| 2 |
"additional_special_tokens": [
|
| 3 |
{
|
| 4 |
-
"content": "<|
|
| 5 |
-
"lstrip": false,
|
| 6 |
-
"normalized": false,
|
| 7 |
-
"rstrip": false,
|
| 8 |
-
"single_word": false
|
| 9 |
-
},
|
| 10 |
-
{
|
| 11 |
-
"content": "<|audio_eos|>",
|
| 12 |
"lstrip": false,
|
| 13 |
"normalized": false,
|
| 14 |
"rstrip": false,
|
| 15 |
"single_word": false
|
| 16 |
},
|
| 17 |
{
|
| 18 |
-
"content": "<|
|
| 19 |
"lstrip": false,
|
| 20 |
"normalized": false,
|
| 21 |
"rstrip": false,
|
| 22 |
"single_word": false
|
| 23 |
},
|
| 24 |
{
|
| 25 |
-
"content": "<|
|
| 26 |
"lstrip": false,
|
| 27 |
"normalized": false,
|
| 28 |
"rstrip": false,
|
|
|
|
| 1 |
{
|
| 2 |
"additional_special_tokens": [
|
| 3 |
{
|
| 4 |
+
"content": "<|audio_start|>",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
"lstrip": false,
|
| 6 |
"normalized": false,
|
| 7 |
"rstrip": false,
|
| 8 |
"single_word": false
|
| 9 |
},
|
| 10 |
{
|
| 11 |
+
"content": "<|reference_start|>",
|
| 12 |
"lstrip": false,
|
| 13 |
"normalized": false,
|
| 14 |
"rstrip": false,
|
| 15 |
"single_word": false
|
| 16 |
},
|
| 17 |
{
|
| 18 |
+
"content": "<|reference_end|>",
|
| 19 |
"lstrip": false,
|
| 20 |
"normalized": false,
|
| 21 |
"rstrip": false,
|
tokenizer.json
CHANGED
|
@@ -158,7 +158,7 @@
|
|
| 158 |
},
|
| 159 |
{
|
| 160 |
"id": 49152,
|
| 161 |
-
"content": "<|
|
| 162 |
"single_word": false,
|
| 163 |
"lstrip": false,
|
| 164 |
"rstrip": false,
|
|
@@ -167,7 +167,7 @@
|
|
| 167 |
},
|
| 168 |
{
|
| 169 |
"id": 49153,
|
| 170 |
-
"content": "<|
|
| 171 |
"single_word": false,
|
| 172 |
"lstrip": false,
|
| 173 |
"rstrip": false,
|
|
@@ -176,16 +176,7 @@
|
|
| 176 |
},
|
| 177 |
{
|
| 178 |
"id": 49154,
|
| 179 |
-
"content": "<|
|
| 180 |
-
"single_word": false,
|
| 181 |
-
"lstrip": false,
|
| 182 |
-
"rstrip": false,
|
| 183 |
-
"normalized": false,
|
| 184 |
-
"special": true
|
| 185 |
-
},
|
| 186 |
-
{
|
| 187 |
-
"id": 49155,
|
| 188 |
-
"content": "<|audio_end|>",
|
| 189 |
"single_word": false,
|
| 190 |
"lstrip": false,
|
| 191 |
"rstrip": false,
|
|
|
|
| 158 |
},
|
| 159 |
{
|
| 160 |
"id": 49152,
|
| 161 |
+
"content": "<|audio_start|>",
|
| 162 |
"single_word": false,
|
| 163 |
"lstrip": false,
|
| 164 |
"rstrip": false,
|
|
|
|
| 167 |
},
|
| 168 |
{
|
| 169 |
"id": 49153,
|
| 170 |
+
"content": "<|reference_start|>",
|
| 171 |
"single_word": false,
|
| 172 |
"lstrip": false,
|
| 173 |
"rstrip": false,
|
|
|
|
| 176 |
},
|
| 177 |
{
|
| 178 |
"id": 49154,
|
| 179 |
+
"content": "<|reference_end|>",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
"single_word": false,
|
| 181 |
"lstrip": false,
|
| 182 |
"rstrip": false,
|
tokenizer_config.json
CHANGED
|
@@ -138,7 +138,7 @@
|
|
| 138 |
"special": true
|
| 139 |
},
|
| 140 |
"49152": {
|
| 141 |
-
"content": "<|
|
| 142 |
"lstrip": false,
|
| 143 |
"normalized": false,
|
| 144 |
"rstrip": false,
|
|
@@ -146,7 +146,7 @@
|
|
| 146 |
"special": true
|
| 147 |
},
|
| 148 |
"49153": {
|
| 149 |
-
"content": "<|
|
| 150 |
"lstrip": false,
|
| 151 |
"normalized": false,
|
| 152 |
"rstrip": false,
|
|
@@ -154,15 +154,7 @@
|
|
| 154 |
"special": true
|
| 155 |
},
|
| 156 |
"49154": {
|
| 157 |
-
"content": "<|
|
| 158 |
-
"lstrip": false,
|
| 159 |
-
"normalized": false,
|
| 160 |
-
"rstrip": false,
|
| 161 |
-
"single_word": false,
|
| 162 |
-
"special": true
|
| 163 |
-
},
|
| 164 |
-
"49155": {
|
| 165 |
-
"content": "<|audio_end|>",
|
| 166 |
"lstrip": false,
|
| 167 |
"normalized": false,
|
| 168 |
"rstrip": false,
|
|
@@ -171,10 +163,9 @@
|
|
| 171 |
}
|
| 172 |
},
|
| 173 |
"additional_special_tokens": [
|
| 174 |
-
"<|audio_sep|>",
|
| 175 |
-
"<|audio_eos|>",
|
| 176 |
"<|audio_start|>",
|
| 177 |
-
"<|
|
|
|
|
| 178 |
],
|
| 179 |
"bos_token": "<|endoftext|>",
|
| 180 |
"clean_up_tokenization_spaces": false,
|
|
|
|
| 138 |
"special": true
|
| 139 |
},
|
| 140 |
"49152": {
|
| 141 |
+
"content": "<|audio_start|>",
|
| 142 |
"lstrip": false,
|
| 143 |
"normalized": false,
|
| 144 |
"rstrip": false,
|
|
|
|
| 146 |
"special": true
|
| 147 |
},
|
| 148 |
"49153": {
|
| 149 |
+
"content": "<|reference_start|>",
|
| 150 |
"lstrip": false,
|
| 151 |
"normalized": false,
|
| 152 |
"rstrip": false,
|
|
|
|
| 154 |
"special": true
|
| 155 |
},
|
| 156 |
"49154": {
|
| 157 |
+
"content": "<|reference_end|>",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
"lstrip": false,
|
| 159 |
"normalized": false,
|
| 160 |
"rstrip": false,
|
|
|
|
| 163 |
}
|
| 164 |
},
|
| 165 |
"additional_special_tokens": [
|
|
|
|
|
|
|
| 166 |
"<|audio_start|>",
|
| 167 |
+
"<|reference_start|>",
|
| 168 |
+
"<|reference_end|>"
|
| 169 |
],
|
| 170 |
"bos_token": "<|endoftext|>",
|
| 171 |
"clean_up_tokenization_spaces": false,
|