# Guide de fine-tuning de la synthèse vocale (TTS)

L'affinage des modèles TTS leur permet de s'adapter à votre jeu de données spécifique, cas d'utilisation ou style et ton souhaités. L'objectif est de personnaliser ces modèles pour cloner des voix, adapter des styles et tons de parole, prendre en charge de nouvelles langues, gérer des tâches spécifiques et plus encore. Nous prenons également en charge **Reconnaissance vocale (STT)** des modèles comme Whisper d'OpenAI.

Avec [Unsloth](https://github.com/unslothai/unsloth), vous pouvez affiner **n'importe quel** modèle TTS (`transformers` compatible) 1,5x plus vite avec 50 % de mémoire en moins que d'autres implémentations grâce à Flash Attention 2.

⭐ **Unsloth prend en charge n'importe quel `transformers` modèle TTS compatible.** Même si nous n'avons pas encore de notebook ou d'upload pour celui-ci, il est tout de même pris en charge, par ex. essayez d'affiner Dia-TTS ou Moshi.

{% hint style="info" %}
Le clonage zero-shot capture le ton mais manque le rythme et l'expression, donnant souvent un rendu robotique et non naturel. L'affinage fournit une réplication vocale bien plus précise et réaliste. [En savoir plus ici](#fine-tuning-voice-models-vs.-zero-shot-voice-cloning).
{% endhint %}

### Notebooks d'affinage :

Nous avons aussi téléversé des modèles TTS (originaux et quantifiés) sur notre [page Hugging Face](https://huggingface.co/collections/unsloth/text-to-speech-tts-models-68007ab12522e96be1e02155).

| [Sesame-CSM (1B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Sesame_CSM_\(1B\)-TTS.ipynb) | [Orpheus-TTS (3B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Orpheus_\(3B\)-TTS.ipynb) | [Whisper Large V3](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Whisper.ipynb) (STT) |
| ------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| [Spark-TTS (0.5B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Spark_TTS_\(0_5B\).ipynb)   | [Llasa-TTS (1B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Llasa_TTS_\(1B\).ipynb)     | [Oute-TTS (1B)](https://colab.research.google.com/github/unslothai/notebooks/blob/main/nb/Oute_TTS_\(1B\).ipynb)  |

{% hint style="success" %}
Si vous remarquez que la durée de sortie atteint un maximum de 10 secondes, augmentez`max_new_tokens = 125` à partir de sa valeur par défaut de 125. Puisque 125 tokens correspondent à 10 secondes d'audio, vous devrez définir une valeur plus élevée pour des sorties plus longues.
{% endhint %}

### Choisir et charger un modèle TTS

Pour le TTS, les modèles plus petits sont souvent préférés en raison d'une latence plus faible et d'une inférence plus rapide pour les utilisateurs finaux. Affiner un modèle de moins de 3 milliards de paramètres est souvent idéal, et nos exemples principaux utilisent Sesame-CSM (1B) et Orpheus-TTS (3B), un modèle de parole basé sur Llama.

#### Détails de Sesame-CSM (1B)

**CSM-1B** est un modèle de base, tandis que **Orpheus-ft** est affiné sur 8 comédiens vocaux professionnels, faisant de la cohérence vocale la principale différence. CSM nécessite un contexte audio pour chaque locuteur pour bien fonctionner, alors qu'Orpheus-ft a cette cohérence intégrée.

L'affinage à partir d'un modèle de base comme CSM nécessite généralement plus de calcul, tandis que partir d'un modèle déjà affiné comme Orpheus-ft offre de meilleurs résultats immédiatement.

Pour aider avec CSM, nous avons ajouté de nouvelles options d'échantillonnage et un exemple montrant comment utiliser le contexte audio pour améliorer la cohérence vocale.

#### Détails d'Orpheus-TTS (3B)

Orpheus est pré-entraîné sur un large corpus de parole et excelle à générer une voix réaliste avec un support intégré pour des indices émotionnels comme les rires et les soupirs. Son architecture en fait l'un des modèles TTS les plus faciles à utiliser et à entraîner car il peut être exporté via llama.cpp, ce qui lui confère une grande compatibilité avec tous les moteurs d'inférence. Pour les modèles non pris en charge, vous ne pourrez sauvegarder que l'adaptateur LoRA au format safetensors.

#### Chargement des modèles

Parce que les modèles vocaux sont généralement de petite taille, vous pouvez entraîner les modèles en utilisant LoRA 16 bits ou un affinage complet FFT qui peut fournir des résultats de meilleure qualité. Pour le charger en LoRA 16 bits :

```python
from unsloth import FastModel

model_name = "unsloth/orpheus-3b-0.1-pretrained"
model, tokenizer = FastModel.from_pretrained(
    model_name,
    load_in_4bit=False  # utiliser la précision 4 bits (QLoRA)
)
```

Quand cela s'exécute, Unsloth téléchargera les poids du modèle ; si vous préférez 8 bits, vous pouvez utiliser `load_in_8bit = True`, ou pour un affinage complet définissez `full_finetuning = True` (assurez-vous d'avoir assez de VRAM). Vous pouvez également remplacer le nom du modèle par d'autres modèles TTS.

{% hint style="info" %}
**Remarque :** Le tokenizer d'Orpheus inclut déjà des tokens spéciaux pour la sortie audio (plus d'informations plus loin). Vous *n'* avez
{% endhint %}

### pas besoin d'un vocodeur séparé – Orpheus produira directement des tokens audio, qui peuvent être décodés en une forme d'onde.

Préparer votre jeu de données **Au minimum, un jeu de données pour l'affinage TTS se compose de** extraits audio et de leurs transcriptions correspondantes [*(texte). Utilisons le* Elise](https://huggingface.co/datasets/MrDragonFox/Elise) jeu de données

* [`qui est un corpus de parole anglaise d'environ 3 heures par un seul locuteur. Il existe deux variantes :`](https://huggingface.co/datasets/MrDragonFox/Elise) MrDragonFox/Elise **– une version augmentée avec** balises d'émotion
* [`(par ex. <sigh>, <laughs>) intégrées dans les transcriptions. Ces balises entre chevrons indiquent des expressions (rire, soupirs, etc.) et sont traitées comme des tokens spéciaux par le tokenizer d'Orpheus`](https://huggingface.co/datasets/Jinsaryko/Elise) Jinsaryko/Elise

– version de base avec des transcriptions sans balises spéciales. `Le jeu de données est organisé avec un audio et une transcription par entrée. Sur Hugging Face, ces jeux de données ont des champs tels que` audio `(la forme d'onde),` texte

{% hint style="success" %}
(la transcription), et quelques métadonnées (nom du locuteur, statistiques de pitch, etc.). Nous devons fournir à Unsloth un jeu de données de paires audio-texte.
{% endhint %}

{% hint style="info" %}
Au lieu de se concentrer uniquement sur le ton, la cadence et le pitch, la priorité devrait être de s'assurer que votre jeu de données est entièrement annoté et correctement normalisé. **Avec certains modèles comme**Sesame-CSM-1B **, vous pourriez remarquer une variation de voix entre les générations en utilisant l'ID locuteur 0 car c'est un**modèle de base **— il n'a pas d'identités vocales fixes. Les tokens d'ID locuteur aident principalement à maintenir**la cohérence au sein d'une conversation

, pas entre des générations séparées. **Pour obtenir une voix cohérente, fournissez**exemples contextuels
{% endhint %}

**, comme quelques extraits audio de référence ou des énoncés antérieurs. Cela aide le modèle à imiter la voix souhaitée de manière plus fiable. Sans cela, la variation est attendue, même avec le même ID locuteur.** Option 1 : Utiliser la bibliothèque Hugging Face Datasets `– Nous pouvons charger le jeu de données Elise en utilisant la` bibliothèque datasets

```python
 :

from datasets import load_dataset, Audio
# Charger le jeu de données Elise (par ex. la version avec balises d'émotion)
dataset = load_dataset("MrDragonFox/Elise", split="train")

print(len(dataset), "échantillons")  # ~1200 échantillons dans Elise
# Assurer que tout l'audio est à 24 kHz (taux attendu par Orpheus)
```

dataset = dataset.cast\_column("audio", Audio(sampling\_rate=24000)) `Elise` Cela téléchargera le jeu de données (\~328 Mo pour \~1,2k échantillons). Chaque élément dans

* `est un dictionnaire contenant au moins :`"audio"
* `: l'extrait audio (tableau d'onde et métadonnées comme la fréquence d'échantillonnage), et`"text"

: la chaîne de transcription `Orpheus prend en charge des balises comme`, `<laugh>`, `<chuckle>`, `<sigh>`, `<cough>`, `<sniffle>`, `<groan>`, `<yawn>`\<gasp> `, etc. Par exemple :`"I missed you \<laugh> so much!" [. Ces balises sont enfermées entre chevrons et seront traitées comme des tokens spéciaux par le modèle (elles correspondent aux](https://github.com/canopyai/Orpheus-TTS) balises attendues par Orpheus `Orpheus prend en charge des balises comme` et `<chuckle>`comme

**). Lors de l'entraînement, le modèle apprendra à associer ces balises aux motifs audio correspondants. Le jeu de données Elise avec balises en contient déjà beaucoup (par ex. 336 occurrences de « laughs », 156 de « sighs », etc. comme listé dans sa fiche). Si votre jeu de données manque de telles balises mais que vous souhaitez les incorporer, vous pouvez annoter manuellement les transcriptions lorsque l'audio contient ces expressions.** Option 2 : Préparer un jeu de données personnalisé

* – Si vous avez vos propres fichiers audio et transcriptions :
* Organisez les extraits audio (fichiers WAV/FLAC) dans un dossier.

  ```
  Créez un fichier CSV ou TSV avec des colonnes pour le chemin de fichier et la transcription. Par exemple :
  filename,text
  0001.wav,Hello there!
  ```
* Utilisez `0002.wav,<sigh> I am very tired.` load\_dataset("csv", data\_files="mydata.csv", split="train") `pour le charger. Il se peut que vous deviez indiquer au chargeur de jeu de données comment gérer les chemins audio. Une alternative est d'utiliser la` fonctionnalité datasets.Audio

  ```python
  pour charger les données audio à la volée :
  from datasets import Audio
  dataset = load_dataset("csv", data_files="mydata.csv", split="train")
  ```

  dataset = dataset.cast\_column("filename", Audio(sampling\_rate=24000)) `Ensuite` dataset\[i]\["audio"]
* **contiendra le tableau audio.** Assurez-vous que les transcriptions sont normalisées

(pas de caractères inhabituels que le tokenizer pourrait ne pas connaître, sauf les balises d'émotion si utilisées). Assurez-vous également que tous les audios ont un taux d'échantillonnage cohérent (re-échantillonnez-les si nécessaire au taux attendu par le modèle, par ex. 24 kHz pour Orpheus). **En résumé, pour la**:

* préparation du jeu de données **Vous avez besoin d'une** liste de (audio, texte)
* paires. `– Nous pouvons charger le jeu de données Elise en utilisant la` Utilisez la bibliothèque HF
* pour gérer le chargement et le prétraitement optionnel (comme le ré-échantillonnage). **Incluez toutes les** balises spéciales `dans le texte que vous voulez que le modèle apprenne (assurez-vous qu'elles sont au format` \<angle\_brackets>
* pour que le modèle les traite comme des tokens distincts).

### (Optionnel) Si multi-locuteur, vous pourriez inclure un token d'ID locuteur dans le texte ou utiliser une approche d'embedding de locuteur séparée, mais cela dépasse ce guide de base (Elise est mono-locuteur).

Affinage TTS avec Unsloth

**Maintenant, commençons l'affinage ! Nous allons illustrer en utilisant du code Python (que vous pouvez exécuter dans un notebook Jupyter, Colab, etc.).**

Étape 1 : Charger le modèle et le jeu de données `Dans tous nos notebooks TTS, nous activons l'entraînement LoRA (16 bits) et désactivons l'entraînement QLoRA (4 bits) avec :`load\_in\_4bit = False

```python
from unsloth import FastLanguageModel
import torch
 . C'est afin que le modèle puisse généralement mieux apprendre votre jeu de données et avoir une plus grande précision.
dtype = None # None pour détection automatique. Float16 pour Tesla T4, V100, Bfloat16 pour Ampere+

model, tokenizer = FastLanguageModel.from_pretrained(
    load_in_4bit = False # Utiliser la quantization 4 bits pour réduire l'utilisation mémoire. Peut être False.
    model_name = "unsloth/orpheus-3b-0.1-ft",
    dtype = dtype,
    load_in_4bit = load_in_4bit,
    max_seq_length= 2048, # Choisissez n'importe quelle valeur pour un contexte long !
)

#token = "hf_...", # en utiliser un si vous utilisez des modèles régulés comme meta-llama/Llama-2-7b-hf
from datasets import load_dataset
```

{% hint style="info" %}
dataset = load\_dataset("MrDragonFox/Elise", split = "train")
{% endhint %}

**Si la mémoire est très limitée ou si le jeu de données est volumineux, vous pouvez streamer ou charger par morceaux. Ici, 3h d'audio tient facilement en RAM. Si vous utilisez votre propre CSV de jeu de données, chargez-le de manière similaire.**

Étape 2 : Avancé - Prétraiter les données pour l'entraînement (Optionnel)

```python
Nous devons préparer des entrées pour le Trainer. Pour le text-to-speech, une approche consiste à entraîner le modèle de manière causale : concaténer les IDs de tokens de texte et d'audio comme séquence cible. Cependant, puisque Orpheus est un LLM à décodage seul qui génère de l'audio, nous pouvons fournir le texte en entrée (contexte) et avoir les IDs de tokens audio comme labels. En pratique, l'intégration d'Unsloth pourrait faire cela automatiquement si la config du modèle l'identifie comme text-to-speech. Sinon, nous pouvons faire quelque chose comme :
# Tokenize the text transcripts
    def preprocess_function(example):
    # Tokenize the text (keep the special tokens like <laugh> intact)
    tokens = tokenizer(example["text"], return_tensors="pt")
    # Flatten to list of token IDs
    input_ids = tokens["input_ids"].squeeze(0)
    # The model will generate audio tokens after these text tokens.
    # For training, we can set labels equal to input_ids (so it learns to predict next token).
    # But that only covers text tokens predicting the next text token (which might be an audio token or end).
    # A more sophisticated approach: append a special token indicating start of audio, and let the model generate the rest.
    # For simplicity, use the same input as labels (the model will learn to output the sequence given itself).

return {"input_ids": input_ids, "labels": input_ids}
```

{% hint style="info" %}
train\_data = dataset.map(preprocess\_function, remove\_columns=dataset.column\_names) *Ce qui précède est une simplification. En réalité, pour affiner correctement Orpheus, vous auriez besoin des*tokens audio comme partie des labels d'entraînement `. La pré-formation d'Orpheus a probablement impliqué la conversion de l'audio en tokens discrets (via un codec audio) et l'entraînement du modèle à les prédire à partir du texte précédent. Pour l'affinage sur de nouvelles données vocales, vous devrez de même obtenir les tokens audio pour chaque extrait (en utilisant le codec audio d'Orpheus). Le GitHub d'Orpheus fournit un script pour le traitement des données – il encode l'audio en séquences de` \<custom\_token\_x>
{% endhint %}

tokens. **Cependant,**&#x55;nsloth peut abstraire cela

: si le modèle est un FastModel avec un processeur associé qui sait comment gérer l'audio, il pourrait automatiquement encoder l'audio du jeu de données en tokens. Sinon, vous devrez encoder manuellement chaque extrait audio en IDs de tokens (en utilisant le codebook d'Orpheus). C'est une étape avancée au-delà de ce guide, mais gardez à l'esprit que l'utilisation simple des tokens de texte n'apprendra pas au modèle l'audio réel – il faut correspondre aux motifs audio. `Supposons qu'Unsloth fournisse un moyen d'alimenter l'audio directement (par exemple, en définissant` processor `et en passant le tableau audio). Si Unsloth ne prend pas encore en charge la tokenisation automatique de l'audio, vous pourriez devoir utiliser la` fonction encode\_audio `du dépôt Orpheus pour obtenir des séquences de tokens pour l'audio, puis utiliser celles-ci comme labels. (Les entrées du jeu de données contiennent bien des` phonemes

**et certaines caractéristiques acoustiques, ce qui suggère une pipeline.)**

```python
Étape 3 : Configurer les arguments d'entraînement et le Trainer
from transformers import TrainingArguments,Trainer,DataCollatorForSeq2Seq

from unsloth import is_bfloat16_supported
    trainer = Trainer(
    model = model,
    train_dataset = dataset,
        args = TrainingArguments(
        gradient_accumulation_steps = 4,
        per_device_train_batch_size = 1,
        warmup_steps = 5,
        # num_train_epochs = 1, # Définissez ceci pour 1 cycle complet d'entraînement.
        max_steps = 60,
        learning_rate = 2e-4,
        fp16 = not is_bfloat16_supported(),
        bf16 = is_bfloat16_supported(),
        optim = "adamw_8bit",
        logging_steps = 1,
        weight_decay = 0.01,','t201':'lr_scheduler_type = "linear",']
        seed = 3407,
        output_dir = "outputs",
        report_to = "none", # Utilisez ceci pour WandB, etc.
    ),
)
```

Nous faisons 60 étapes pour accélérer les choses, mais vous pouvez définir `num_train_epochs=1` pour une exécution complète, et désactiver `max_steps=None`. L'utilisation d'un per\_device\_train\_batch\_size >1 peut entraîner des erreurs si configuration multi-GPU ; pour éviter les problèmes, assurez-vous que CUDA\_VISIBLE\_DEVICES est réglé sur un seul GPU (par ex., CUDA\_VISIBLE\_DEVICES=0). Ajustez au besoin.

**Étape 4 : Commencer l'affinage**

Cela démarrera la boucle d'entraînement. Vous devriez voir des journaux de perte toutes les 50 étapes (comme défini par `logging_steps`). L'entraînement peut prendre du temps selon le GPU – par exemple, sur un GPU T4 de Colab, quelques époques sur 3h de données peuvent prendre 1 à 2 heures. Les optimisations d'Unsloth le rendront plus rapide que l'entraînement HF standard.

**Étape 5 : Sauvegarder le modèle affiné**

Après la fin de l'entraînement (ou si vous l'arrêtez en cours lorsque vous jugez que c'est suffisant), sauvegardez le modèle. Cela sauvegarde UNIQUEMENT les adaptateurs LoRA, et non le modèle complet. Pour sauvegarder en 16 bits ou GGUF, faites défiler vers le bas !

```python
model.save_pretrained("lora_model")  # Sauvegarde locale
tokenizer.save_pretrained("lora_model")
# model.push_to_hub("your_name/lora_model", token = "...") # Sauvegarde en ligne
# tokenizer.push_to_hub("your_name/lora_model", token = "...") # Sauvegarde en ligne
```

Ceci enregistre les poids du modèle (pour LoRA, il peut n'enregistrer que les poids des adaptateurs si la base n'est pas entièrement affinée). Si vous avez utilisé `--push_model` dans la CLI ou `trainer.push_to_hub()`, vous pouvez le téléverser directement sur Hugging Face Hub.

Vous devriez maintenant avoir un modèle TTS affiné dans le répertoire. L'étape suivante est de le tester et, si pris en charge, vous pouvez utiliser llama.cpp pour le convertir en fichier GGUF.

### Affinage des modèles vocaux vs clonage vocal zero-shot

Les gens disent que vous pouvez cloner une voix avec seulement 30 secondes d'audio en utilisant des modèles comme XTTS - sans entraînement requis. C'est techniquement vrai, mais cela manque le point essentiel.

Le clonage vocal zero-shot, disponible aussi dans des modèles comme Orpheus et CSM, est une approximation. Il capture le **ton et le timbre** d'une voix, mais il ne reproduit pas toute la gamme expressive. Vous perdez des détails comme la vitesse d'élocution, le phrasé, les particularités vocales et les subtilités de la prosodie - des éléments qui donnent à une voix sa **personnalité et son caractère unique**.

Si vous voulez juste une voix différente et que les mêmes schémas de livraison vous conviennent, le zero-shot suffit généralement. Mais la parole suivra toujours le **style du modèle**, et non celui du locuteur.

Pour tout ce qui est plus personnalisé ou expressif, vous avez besoin d'un entraînement avec des méthodes comme LoRA pour vraiment capturer la façon dont quelqu'un parle.
