Instructions to use ketav/chatterbox-turbo-hinglish with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Chatterbox
How to use ketav/chatterbox-turbo-hinglish with Chatterbox:
# pip install chatterbox-tts import torchaudio as ta from chatterbox.tts import ChatterboxTTS model = ChatterboxTTS.from_pretrained(device="cuda") text = "Ezreal and Jinx teamed up with Ahri, Yasuo, and Teemo to take down the enemy's Nexus in an epic late-game pentakill." wav = model.generate(text) ta.save("test-1.wav", wav, model.sr) # If you want to synthesize with a different voice, specify the audio prompt AUDIO_PROMPT_PATH="YOUR_FILE.wav" wav = model.generate(text, audio_prompt_path=AUDIO_PROMPT_PATH) ta.save("test-2.wav", wav, model.sr) - Notebooks
- Google Colab
- Kaggle
Chatterbox Turbo finetuned for Hindi/Hinglish TTS (romanized text)
Browse files- .gitattributes +1 -0
- README.md +147 -0
- TRAINING_NOTES.md +135 -0
- config.py +42 -0
- inference.py +107 -0
- reference.wav +3 -0
- t3_turbo_finetuned.safetensors +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
reference.wav filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
language:
|
| 3 |
+
- hi
|
| 4 |
+
- en
|
| 5 |
+
license: mit
|
| 6 |
+
tags:
|
| 7 |
+
- tts
|
| 8 |
+
- text-to-speech
|
| 9 |
+
- voice-cloning
|
| 10 |
+
- hindi
|
| 11 |
+
- hinglish
|
| 12 |
+
- chatterbox
|
| 13 |
+
base_model: ResembleAI/chatterbox-turbo
|
| 14 |
+
pipeline_tag: text-to-speech
|
| 15 |
+
---
|
| 16 |
+
|
| 17 |
+
# Chatterbox Turbo — Hindi/Hinglish Finetuned
|
| 18 |
+
|
| 19 |
+
Finetuned [Chatterbox Turbo](https://huggingface.co/ResembleAI/chatterbox-turbo) (350M, GPT-2 backbone) for **Hindi (romanized) and English** text-to-speech with voice cloning.
|
| 20 |
+
|
| 21 |
+
## Key Features
|
| 22 |
+
- **Bilingual**: Speaks both Hindi (romanized Latin script) and English
|
| 23 |
+
- **Hinglish**: Handles code-mixed Hindi-English seamlessly
|
| 24 |
+
- **Voice Cloning**: Provide any 5-10s reference audio to clone the voice
|
| 25 |
+
- **Fast**: Single-step decoder, ~6x faster than real-time on GPU
|
| 26 |
+
|
| 27 |
+
## How It Works
|
| 28 |
+
Hindi text is written in **romanized form** (Latin script), not Devanagari. This allows the GPT-2 BPE tokenizer to handle it natively without any vocabulary extension.
|
| 29 |
+
|
| 30 |
+
Example: `"bharat ke kisan bahut mehnat karte hai"` instead of `"भारत के किसान बहुत मेहनत करते हैं"`
|
| 31 |
+
|
| 32 |
+
## Usage
|
| 33 |
+
|
| 34 |
+
### Prerequisites
|
| 35 |
+
```bash
|
| 36 |
+
pip install chatterbox-tts safetensors torch torchaudio soundfile
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
### Quick Inference
|
| 40 |
+
```python
|
| 41 |
+
import torch
|
| 42 |
+
import soundfile as sf
|
| 43 |
+
from safetensors.torch import load_file
|
| 44 |
+
from chatterbox.tts_turbo import ChatterboxTurboTTS
|
| 45 |
+
from chatterbox.models.t3.t3 import T3
|
| 46 |
+
|
| 47 |
+
# Load base Chatterbox Turbo
|
| 48 |
+
engine = ChatterboxTurboTTS.from_pretrained(device="cuda")
|
| 49 |
+
|
| 50 |
+
# Load finetuned T3 weights
|
| 51 |
+
t3_config = engine.t3.hp
|
| 52 |
+
t3_config.text_tokens_dict_size = 50276
|
| 53 |
+
new_t3 = T3(hp=t3_config)
|
| 54 |
+
if hasattr(new_t3.tfmr, "wte"):
|
| 55 |
+
del new_t3.tfmr.wte
|
| 56 |
+
|
| 57 |
+
state_dict = load_file("t3_turbo_finetuned.safetensors", device="cpu")
|
| 58 |
+
new_t3.load_state_dict(state_dict, strict=True)
|
| 59 |
+
|
| 60 |
+
engine.t3 = new_t3
|
| 61 |
+
engine.t3.to("cuda").eval()
|
| 62 |
+
|
| 63 |
+
# Generate speech
|
| 64 |
+
wav = engine.generate(
|
| 65 |
+
text="yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai.",
|
| 66 |
+
audio_prompt_path="reference.wav", # 5-10s reference clip of target voice
|
| 67 |
+
temperature=0.5,
|
| 68 |
+
)
|
| 69 |
+
sf.write("output.wav", wav.squeeze().cpu().numpy(), 24000)
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
### Text Format
|
| 73 |
+
- **Hindi**: Use romanized text (Latin script). Example: `"namaste, mera naam Ketav hai"`
|
| 74 |
+
- **English**: Use as-is. Example: `"Hello, my name is Ketav"`
|
| 75 |
+
- **Hinglish**: Mix freely. Example: `"mujhe lagta hai ki yeh project bahut successful hoga"`
|
| 76 |
+
|
| 77 |
+
### Romanization Guide
|
| 78 |
+
Common Hindi romanization patterns used in training:
|
| 79 |
+
|
| 80 |
+
| Hindi | Romanized |
|
| 81 |
+
|-------|-----------|
|
| 82 |
+
| है | hai |
|
| 83 |
+
| में | mein |
|
| 84 |
+
| यह | yeh |
|
| 85 |
+
| वो | voh |
|
| 86 |
+
| नहीं | nahi |
|
| 87 |
+
| बहुत | bahut |
|
| 88 |
+
| क्योंकि | kyonki |
|
| 89 |
+
|
| 90 |
+
### Inference Tips
|
| 91 |
+
- **Temperature 0.5** recommended (lower = more precise pronunciation)
|
| 92 |
+
- Reference audio must be **>5 seconds**
|
| 93 |
+
- Clean reference audio with minimal background noise works best
|
| 94 |
+
|
| 95 |
+
## Training Details
|
| 96 |
+
|
| 97 |
+
### Data
|
| 98 |
+
- **14,085 samples** (~20.4 hours) from a single male Hindi/English speaker
|
| 99 |
+
- 7,320 Hindi samples (romanized via IndicXlit + loanword dictionary)
|
| 100 |
+
- 6,765 English samples (original text)
|
| 101 |
+
- Duration filtered to 1-15 seconds per clip
|
| 102 |
+
|
| 103 |
+
### Text Processing Pipeline
|
| 104 |
+
1. Indic Normalize (DevanagariNormalizer)
|
| 105 |
+
2. English loanword replacement (23,019 entry dictionary)
|
| 106 |
+
3. IndicXlit transliteration cache (235,973 entries)
|
| 107 |
+
4. Lowercase + standardize romanization (62 rules)
|
| 108 |
+
|
| 109 |
+
### Hyperparameters
|
| 110 |
+
- Base model: `ResembleAI/chatterbox-turbo`
|
| 111 |
+
- Vocab size: 50,276 (original GPT-2, no extension)
|
| 112 |
+
- Batch size: 16, gradient accumulation: 2 (effective 32)
|
| 113 |
+
- Learning rate: 5e-5
|
| 114 |
+
- Epochs: 100
|
| 115 |
+
- Best checkpoint: step 38,000, loss 0.6685
|
| 116 |
+
- GPU: NVIDIA RTX 3090 (24GB)
|
| 117 |
+
- Training time: ~14 hours
|
| 118 |
+
|
| 119 |
+
### Loss Curve
|
| 120 |
+
| Epoch | Loss |
|
| 121 |
+
|-------|------|
|
| 122 |
+
| 1 | 7.204 |
|
| 123 |
+
| 10 | 3.672 |
|
| 124 |
+
| 20 | 2.162 |
|
| 125 |
+
| 30 | 1.519 |
|
| 126 |
+
| 50 | 0.938 |
|
| 127 |
+
| 80 | 0.669 |
|
| 128 |
+
|
| 129 |
+
## Files
|
| 130 |
+
| File | Description |
|
| 131 |
+
|------|-------------|
|
| 132 |
+
| `t3_turbo_finetuned.safetensors` | Finetuned T3 model weights (1.6 GB) |
|
| 133 |
+
| `inference.py` | Inference script with test sentences |
|
| 134 |
+
| `reference.wav` | Sample reference audio for voice cloning |
|
| 135 |
+
| `config.py` | Training configuration used |
|
| 136 |
+
| `TRAINING_NOTES.md` | Detailed training documentation |
|
| 137 |
+
|
| 138 |
+
## Limitations
|
| 139 |
+
- Only handles **romanized** Hindi text, not Devanagari script
|
| 140 |
+
- Voice quality depends on reference audio quality
|
| 141 |
+
- May merge words at high temperature (use 0.5)
|
| 142 |
+
- Trained on single male speaker — works for voice cloning of any voice, but Hindi pronunciation patterns are from one speaker
|
| 143 |
+
|
| 144 |
+
## Acknowledgments
|
| 145 |
+
- [Resemble AI](https://www.resemble.ai/) for Chatterbox Turbo
|
| 146 |
+
- [gokhaneraslan/chatterbox-finetuning](https://github.com/gokhaneraslan/chatterbox-finetuning) for the finetuning toolkit
|
| 147 |
+
- [AI4Bharat IndicXlit](https://github.com/AI4Bharat/IndicXlit) for transliteration
|
TRAINING_NOTES.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Chatterbox Turbo Hinglish Finetuning — Training Notes
|
| 2 |
+
|
| 3 |
+
## Overview
|
| 4 |
+
Finetuning Chatterbox Turbo (350M, GPT-2 backbone) for **Hindi (romanized) + English** TTS using a single male speaker.
|
| 5 |
+
|
| 6 |
+
## Data Pipeline
|
| 7 |
+
|
| 8 |
+
### Source Data
|
| 9 |
+
- **Hindi male**: 7,320 files from `/workspace/data/bilingual/hindi/wav_22k/` (train_hindimale_*.wav)
|
| 10 |
+
- **English male**: 6,765 files from `/workspace/data/bilingual/english/wav_22k/` (train_hindifullmale_*.wav)
|
| 11 |
+
- **Total**: 14,085 files, ~21.3 hours → filtered to 13,941 (1-15s duration), ~20.4 hours
|
| 12 |
+
- **Audio format**: 22kHz mono WAV (auto-resampled to 16kHz by Chatterbox)
|
| 13 |
+
- **Speaker**: Single male speaker (speaker ID 1)
|
| 14 |
+
|
| 15 |
+
### Text Processing Pipeline (Hindi only, English left intact)
|
| 16 |
+
1. **Indic Normalize** — DevanagariNormalizer from IndicNLP (nukta decomposition, visarga fixes)
|
| 17 |
+
2. **Loanword Replacement** — 23,019 entry Devanagari→English dictionary (`scripts/utils/english_loanwords.py` from asr-main repo)
|
| 18 |
+
3. **Transliteration** — xlit_cache_merged.json (235,973 entries) maps remaining Devanagari words to romanized Latin
|
| 19 |
+
4. **Lowercase** — all Hindi text lowercased
|
| 20 |
+
5. **Standardize Romanization** — 62 rules for common variations (hain→hai, vo→voh, bahot→bahut, etc.)
|
| 21 |
+
6. **English text** — left completely untouched from source manifests
|
| 22 |
+
|
| 23 |
+
### Coverage
|
| 24 |
+
- xlit cache: 91,323 tokens (96.9%)
|
| 25 |
+
- Loanword dict: 2,857 tokens (3.0%)
|
| 26 |
+
- Missing: 1 token (junk `__वें`)
|
| 27 |
+
- **Total: 100% coverage**
|
| 28 |
+
|
| 29 |
+
### Dataset Format
|
| 30 |
+
- **LJSpeech format**: `metadata.csv` (filename|text|text) + `wavs/` directory (symlinks)
|
| 31 |
+
- Sorted by duration (ascending) to minimize padding waste
|
| 32 |
+
- Uploaded to HuggingFace: `ketav/hinglish-tts-data/romanized_transcripts_hindimale.zip`
|
| 33 |
+
|
| 34 |
+
## Model Configuration
|
| 35 |
+
|
| 36 |
+
### No Vocab Extension Needed
|
| 37 |
+
- All text is Latin characters (romanized Hindi + English)
|
| 38 |
+
- GPT-2 BPE tokenizer handles this natively
|
| 39 |
+
- `new_vocab_size = 50276` (matches pretrained T3 turbo exactly)
|
| 40 |
+
- Skipped the `setup.py` vocab merging step entirely
|
| 41 |
+
|
| 42 |
+
### Training Config
|
| 43 |
+
```python
|
| 44 |
+
is_turbo = True
|
| 45 |
+
new_vocab_size = 50276
|
| 46 |
+
batch_size = 16
|
| 47 |
+
grad_accum = 2 # effective batch = 32
|
| 48 |
+
learning_rate = 5e-5
|
| 49 |
+
num_epochs = 100
|
| 50 |
+
save_steps = 1000
|
| 51 |
+
max_speech_len = 850
|
| 52 |
+
max_text_len = 256
|
| 53 |
+
prompt_duration = 3.0 # seconds
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
### Speed Optimizations Applied
|
| 57 |
+
- `torch.backends.cuda.matmul.allow_tf32 = True` (~15% faster)
|
| 58 |
+
- `torch.set_float32_matmul_precision('high')`
|
| 59 |
+
- `bf16 = True` (mixed precision)
|
| 60 |
+
- `gradient_checkpointing = True` (VRAM savings)
|
| 61 |
+
- Duration-sorted data (less padding waste)
|
| 62 |
+
- Filtered clips to 1-15s (removed 144 extreme outliers)
|
| 63 |
+
- `torch.compile` — tried but incompatible with T3 model (CUDAGraphs conflict)
|
| 64 |
+
|
| 65 |
+
### GPU
|
| 66 |
+
- NVIDIA RTX 3090 (24GB)
|
| 67 |
+
- VRAM usage: ~13.8 GB peak (with batch_size=16)
|
| 68 |
+
- GPU utilization: 96-100%
|
| 69 |
+
- Training speed: ~1.17-1.23 s/step
|
| 70 |
+
|
| 71 |
+
## Training Progress
|
| 72 |
+
|
| 73 |
+
### Loss Curve
|
| 74 |
+
| Epoch | Loss |
|
| 75 |
+
|-------|--------|
|
| 76 |
+
| 1 | 7.204 |
|
| 77 |
+
| 5 | 5.042 |
|
| 78 |
+
| 10 | 3.672 |
|
| 79 |
+
| 20 | 2.162 |
|
| 80 |
+
| 30 | 1.519 |
|
| 81 |
+
| 40 | 1.127 |
|
| 82 |
+
| 50 | 0.938 |
|
| 83 |
+
| 60 | 0.822 |
|
| 84 |
+
|
| 85 |
+
### Checkpoints
|
| 86 |
+
Best checkpoints saved to `best_models/` by automated checkpoint_saver.py script.
|
| 87 |
+
Backup copy at `/workspace/best_models_backup/`.
|
| 88 |
+
|
| 89 |
+
## Inference
|
| 90 |
+
|
| 91 |
+
### Reference Audio
|
| 92 |
+
- Must be >5 seconds (Chatterbox Turbo requirement)
|
| 93 |
+
- Using `train_hindimale_04569.wav` (6.28s Hindi male clip)
|
| 94 |
+
|
| 95 |
+
### Best Settings
|
| 96 |
+
```python
|
| 97 |
+
temperature = 0.5 # lower = more precise, less word-merging artifacts
|
| 98 |
+
# exaggeration and repetition_penalty are ignored by Turbo mode
|
| 99 |
+
```
|
| 100 |
+
|
| 101 |
+
### Known Issues
|
| 102 |
+
- **Word merging**: At temperature 0.8, words can blend together (e.g., "company ka growth" → "compgrowth")
|
| 103 |
+
- **Fix**: Lower temperature to 0.5 resolves this
|
| 104 |
+
- Turbo mode ignores `exaggeration`, `cfg_weight`, and `min_p` parameters
|
| 105 |
+
|
| 106 |
+
### Test Sentences Used
|
| 107 |
+
```
|
| 108 |
+
Hindi: "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai."
|
| 109 |
+
Hindi: "bharat ke kisan bahut mehnat karte hai lekin unhe sahi daam nahi milta."
|
| 110 |
+
English: "The weather today is beautiful and I feel very happy about it."
|
| 111 |
+
English: "Technology has changed our lives in ways we never imagined before."
|
| 112 |
+
Hinglish: "mujhe lagta hai ki yeh project bahut successful hoga because humne bahut hard work kiya hai."
|
| 113 |
+
Hinglish: "aaj meeting mein boss ne kaha ki next quarter mein company ka growth double hoga."
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
## Monitoring
|
| 117 |
+
- **Telegram bot**: Sends training updates every 30 min (loss, LR, epoch, progress)
|
| 118 |
+
- **Checkpoint saver**: Keeps best 3 checkpoints by loss, detects overfitting (3 consecutive loss increases)
|
| 119 |
+
- **TensorBoard**: `tensorboard --logdir chatterbox_output --port 6006`
|
| 120 |
+
|
| 121 |
+
## Files Created
|
| 122 |
+
| File | Purpose |
|
| 123 |
+
|------|---------|
|
| 124 |
+
| `src/config.py` | Training configuration |
|
| 125 |
+
| `train.py` | Modified with resume support, tf32, torch.load patch |
|
| 126 |
+
| `test_inference.py` | Mid-training inference from best checkpoint |
|
| 127 |
+
| `telegram_monitor.py` | Telegram training status updates |
|
| 128 |
+
| `checkpoint_saver.py` | Best checkpoint tracking + overfitting detection |
|
| 129 |
+
| `TRAINING_NOTES.md` | This file |
|
| 130 |
+
|
| 131 |
+
## Key Repos & Data
|
| 132 |
+
- **Finetuning repo**: gokhaneraslan/chatterbox-finetuning
|
| 133 |
+
- **ASR pipeline (text processing)**: `/workspace/asr-main/asr-main/`
|
| 134 |
+
- **HF dataset**: `ketav/hinglish-tts-data` (private)
|
| 135 |
+
- **HF parakeet data**: `ketav/hinglish-parakeet-tarred`, `ketav/hinglish-v2-sorted-tarred`
|
config.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from dataclasses import dataclass
|
| 2 |
+
|
| 3 |
+
@dataclass
|
| 4 |
+
class TrainConfig:
|
| 5 |
+
# --- Paths ---
|
| 6 |
+
model_dir: str = "./pretrained_models"
|
| 7 |
+
csv_path: str = "/workspace/chatterbox_dataset/metadata.csv"
|
| 8 |
+
metadata_path: str = "./metadata.json"
|
| 9 |
+
wav_dir: str = "/workspace/chatterbox_dataset/wavs"
|
| 10 |
+
preprocessed_dir = "/workspace/chatterbox_dataset/preprocess"
|
| 11 |
+
output_dir: str = "./chatterbox_output"
|
| 12 |
+
|
| 13 |
+
is_inference = False
|
| 14 |
+
inference_prompt_path: str = "./speaker_reference/reference.wav"
|
| 15 |
+
inference_test_text: str = "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai."
|
| 16 |
+
|
| 17 |
+
ljspeech = True
|
| 18 |
+
json_format = False
|
| 19 |
+
preprocess = False
|
| 20 |
+
|
| 21 |
+
is_turbo: bool = True
|
| 22 |
+
|
| 23 |
+
# --- Vocabulary ---
|
| 24 |
+
# Match pretrained T3 turbo vocab size exactly (GPT-2 50257 + 19 special tokens)
|
| 25 |
+
new_vocab_size: int = 50276
|
| 26 |
+
|
| 27 |
+
# --- Hyperparameters ---
|
| 28 |
+
batch_size: int = 16 # RTX 3090 24GB — plenty of headroom
|
| 29 |
+
grad_accum: int = 2 # Effective batch = 32
|
| 30 |
+
learning_rate: float = 5e-5
|
| 31 |
+
num_epochs: int = 100
|
| 32 |
+
|
| 33 |
+
save_steps: int = 1000
|
| 34 |
+
save_total_limit: int = 20
|
| 35 |
+
dataloader_num_workers: int = 8
|
| 36 |
+
|
| 37 |
+
# --- Constraints ---
|
| 38 |
+
start_text_token = 255
|
| 39 |
+
stop_text_token = 0
|
| 40 |
+
max_text_len: int = 256
|
| 41 |
+
max_speech_len: int = 850
|
| 42 |
+
prompt_duration: float = 3.0
|
inference.py
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Quick inference test using best checkpoint. Runs separately from training."""
|
| 3 |
+
|
| 4 |
+
import os
|
| 5 |
+
import glob
|
| 6 |
+
import torch
|
| 7 |
+
import numpy as np
|
| 8 |
+
import soundfile as sf
|
| 9 |
+
from safetensors.torch import load_file
|
| 10 |
+
|
| 11 |
+
from src.config import TrainConfig
|
| 12 |
+
from src.chatterbox_.tts_turbo import ChatterboxTurboTTS
|
| 13 |
+
from src.chatterbox_.models.t3.t3 import T3
|
| 14 |
+
from src.utils import trim_silence_with_vad
|
| 15 |
+
|
| 16 |
+
# Patch torch.load for compatibility
|
| 17 |
+
_original_torch_load = torch.load
|
| 18 |
+
torch.load = lambda *args, **kwargs: _original_torch_load(*args, **{**kwargs, "weights_only": kwargs.get("weights_only", False)})
|
| 19 |
+
|
| 20 |
+
cfg = TrainConfig()
|
| 21 |
+
DEVICE = "cuda"
|
| 22 |
+
REFERENCE_AUDIO = "./speaker_reference/reference.wav"
|
| 23 |
+
OUTPUT_DIR = "/workspace/inference_test_v3"
|
| 24 |
+
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
| 25 |
+
|
| 26 |
+
# Test sentences
|
| 27 |
+
TEST_SENTENCES = {
|
| 28 |
+
"hindi_1": "yeh ek bahut acchi baat hai ki hum sab milkar kaam kar rahe hai.",
|
| 29 |
+
"hindi_2": "bharat ke kisan bahut mehnat karte hai lekin unhe sahi daam nahi milta.",
|
| 30 |
+
"english_1": "The weather today is beautiful and I feel very happy about it.",
|
| 31 |
+
"english_2": "Technology has changed our lives in ways we never imagined before.",
|
| 32 |
+
"hinglish_1": "mujhe lagta hai ki yeh project bahut successful hoga because humne bahut hard work kiya hai.",
|
| 33 |
+
"hinglish_2": "aaj meeting mein boss ne kaha ki next quarter mein company ka growth double hoga.",
|
| 34 |
+
}
|
| 35 |
+
|
| 36 |
+
def find_best_checkpoint():
|
| 37 |
+
"""Find the best checkpoint from best_models/ or latest from training."""
|
| 38 |
+
best_dir = "/workspace/chatterbox-finetuning/best_models"
|
| 39 |
+
if os.path.exists(best_dir):
|
| 40 |
+
ckpts = sorted(glob.glob(f"{best_dir}/best_loss*"), key=lambda x: float(x.split("loss")[1].split("_")[0]))
|
| 41 |
+
if ckpts:
|
| 42 |
+
# Find the safetensors file inside
|
| 43 |
+
for f in os.listdir(ckpts[0]):
|
| 44 |
+
if f.endswith(".safetensors") and "model" in f:
|
| 45 |
+
return os.path.join(ckpts[0], f)
|
| 46 |
+
# Try trainer format
|
| 47 |
+
model_path = os.path.join(ckpts[0], "model.safetensors")
|
| 48 |
+
if os.path.exists(model_path):
|
| 49 |
+
return model_path
|
| 50 |
+
return None
|
| 51 |
+
|
| 52 |
+
def load_engine(checkpoint_path):
|
| 53 |
+
print(f"Loading base model...")
|
| 54 |
+
engine = ChatterboxTurboTTS.from_local(cfg.model_dir, device="cpu")
|
| 55 |
+
|
| 56 |
+
print(f"Creating T3 with vocab size: {cfg.new_vocab_size}")
|
| 57 |
+
t3_config = engine.t3.hp
|
| 58 |
+
t3_config.text_tokens_dict_size = cfg.new_vocab_size
|
| 59 |
+
new_t3 = T3(hp=t3_config)
|
| 60 |
+
|
| 61 |
+
if hasattr(new_t3.tfmr, "wte"):
|
| 62 |
+
del new_t3.tfmr.wte
|
| 63 |
+
|
| 64 |
+
print(f"Loading checkpoint: {checkpoint_path}")
|
| 65 |
+
state_dict = load_file(checkpoint_path, device="cpu")
|
| 66 |
+
# Strip "t3." prefix if saved by HF Trainer wrapper
|
| 67 |
+
if any(k.startswith("t3.") for k in state_dict):
|
| 68 |
+
state_dict = {k.replace("t3.", "", 1): v for k, v in state_dict.items()}
|
| 69 |
+
new_t3.load_state_dict(state_dict, strict=True)
|
| 70 |
+
|
| 71 |
+
engine.t3 = new_t3
|
| 72 |
+
engine.t3.to(DEVICE).eval()
|
| 73 |
+
engine.s3gen.to(DEVICE).eval()
|
| 74 |
+
engine.ve.to(DEVICE).eval()
|
| 75 |
+
engine.device = DEVICE
|
| 76 |
+
|
| 77 |
+
return engine
|
| 78 |
+
|
| 79 |
+
def generate(engine, text, output_path):
|
| 80 |
+
with torch.no_grad():
|
| 81 |
+
wav = engine.generate(
|
| 82 |
+
text=text,
|
| 83 |
+
audio_prompt_path=REFERENCE_AUDIO,
|
| 84 |
+
temperature=0.5,
|
| 85 |
+
)
|
| 86 |
+
wav_np = wav.squeeze().cpu().numpy()
|
| 87 |
+
wav_np = trim_silence_with_vad(wav_np, engine.sr)
|
| 88 |
+
sf.write(output_path, wav_np, engine.sr)
|
| 89 |
+
return len(wav_np) / engine.sr
|
| 90 |
+
|
| 91 |
+
if __name__ == "__main__":
|
| 92 |
+
ckpt = find_best_checkpoint()
|
| 93 |
+
if not ckpt:
|
| 94 |
+
print("No checkpoint found!")
|
| 95 |
+
exit(1)
|
| 96 |
+
|
| 97 |
+
print(f"Best checkpoint: {ckpt}")
|
| 98 |
+
engine = load_engine(ckpt)
|
| 99 |
+
|
| 100 |
+
print(f"\nGenerating {len(TEST_SENTENCES)} test sentences...\n")
|
| 101 |
+
for name, text in TEST_SENTENCES.items():
|
| 102 |
+
out_path = os.path.join(OUTPUT_DIR, f"{name}.wav")
|
| 103 |
+
dur = generate(engine, text, out_path)
|
| 104 |
+
print(f" {name}: {dur:.1f}s -> {out_path}")
|
| 105 |
+
print(f" Text: {text}")
|
| 106 |
+
|
| 107 |
+
print(f"\nDone! Audio files in {OUTPUT_DIR}/")
|
reference.wav
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ad65adc16d23ab41aa6e2f32ec19e51400acdb862e1055a724a776bd02997f71
|
| 3 |
+
size 277188
|
t3_turbo_finetuned.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a0ce1dd72db44baa59f4aa1996a64ca4ac5f69113117927f93b4236021f6c87f
|
| 3 |
+
size 1709549468
|