Parler-TTS 微调和推理技巧

Parler-TTS 项目很高兴地宣布发布两个新的文本转语音模型!本文介绍如何使用Gemma制作自己的数据集,如何微调Parler-TTS,以及如何使用Parler-TTS模型进行推理。

1、Parler-TTS 模型简介

首先,我们有 Parler-TTS Mini v0.1,这是一款轻量级模型,非常适合快速轻松地生成语音。受最近研究论文《使用合成标注的高保真文本转语音的自然语言指导》的启发,Parler-TTS Mini v0.1 让你通过简单的文本提示直观地控制各种语音方面,例如性别、背景噪音和语速。

对于那些寻求最大表现力和控制力的人,我们还有 Parler-TTS Large v1。这个 2.2B 参数模型经过大量 45K 小时的音频数据训练,可提供真正高质量、听起来自然的语音,并可广泛控制各种特征,包括性别、背景噪音、语速、音调和混响。

使用合成标注的高保真文本转语音的自然语言指导论文介绍了一种新颖的文本转语音 (TTS) 系统,该系统通过利用大规模数据集和自然语言描述实现高保真和多样化的语音生成。

动机:现有的 TTS 系统通常依赖参考音频来控制说话者的身份和风格,限制了它们的创造性应用。虽然自然语言提示提供了更直观的解决方案,但之前的尝试受到缺乏具有语音属性详细自然语言描述的大规模数据集的限制。

主要贡献:

  • 自动标记:作者通过提出一种可扩展的方法来解决数据稀缺问题,该方法用于自动标记大量 45k 小时的语音数据集 (Multilingual LibriSpeech),其中包含性别、口音、语速、音调和录音质量等各种属性。它们还包括一个较小的高保真数据集 (LibriTTS-R),以提高音频质量。
  • 语音语言模型:此标记数据集用于训练改编自通用音频生成库 AudioCraft 的语音语言模型。模型架构使用仅解码器的 Transformer 网络。与以前的工作不同,该模型仅依靠自然语言描述来控制语音属性,没有任何参考音频嵌入。
  • 高保真音频:该系统利用 Descript Audio Codec (DAC) 生成高保真音频,即使在有限的高保真训练数据下,也能比以前的方法取得显着改进。

模型架构:

TTS 系统采用仅解码器的 Transformer 架构。输入包括:

  • 转录文本:要合成的文本,附加在输入序列的前面。
  • 描述文本:所需语音特征的自然语言描述(例如,“一个带有英国口音的男人用活泼的语调说话”)。这由预先训练的 T5 文本编码器处理,并通过交叉注意馈送到解码器。

解码器的输出是一系列代表音频特征的离散标记,然后使用 DAC 解码器将其转换为音频波形。

训练:

该模型在大规模标记数据集上进行训练。训练过程涉及优化模型以生成与提供的文本记录和描述准确匹配的语音。

评估:

使用客观和主观指标对系统进行评估:

  • 客观评估:性别和口音分类的准确性、合成和描述属性之间的相关性以及音频保真度指标(PESQ、STOI、SI-SDR)。
  • 主观评估:听力测试以评估生成的语音与描述(REL)和整体自然度(MOS)的相关性。

结果:

结果表明,该系统可以生成具有各种口音、韵律风格和录音条件的高保真语音,由直观的自然语言描述控制。它在音频保真度和描述匹配准确度方面都优于并发工作。

2、Parler-TTS 推理

首先,安装 Parler-TTS 包:

! pip install git+https://github.com/huggingface/parler-tts.git

并导入必要的模块:

import torch
from parler_tts import ParlerTTSForConditionalGeneration, ParlerTTSStreamer
from transformers import AutoTokenizer
from threading import Thread
import soundfile as sf

然后设置你喜欢的 torch_device、torch_dtype 和 model_name。我们还为填充设置了 max_length 并加载预训练模型和 tokenizer。最后,我们从模型配置中获取采样率和帧速率。

torch_device = "cuda:0" # Use "mps" for Mac
torch_dtype = torch.bfloat16
model_name = "parler-tts/parler-tts-mini-v1"

# need to set padding max length
max_length = 50

# load model and tokenizer
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = ParlerTTSForConditionalGeneration.from_pretrained(
    model_name,
).to(torch_device, dtype=torch_dtype)

sampling_rate = model.audio_encoder.config.sampling_rate
frame_rate = model.audio_encoder.config.frame_rate

2.1 使用随机声音生成语音

现在,让我们生成一些语音。提供文本提示和所需声音和说话风格的描述。描述被标记并输入到模型中,模型会生成相应的音频。然后,你可以直接在笔记本中收听生成的音频。点击此处查看。

from IPython.display import Audio

prompt = "Hey, how are you doing today?"
description = "A female speaker delivers a slightly expressive and animated speech with a moderate speed and pitch. The recording is of very high quality, with the speaker's voice sounding clear and very close up."

input_ids = tokenizer(description, return_tensors="pt").input_ids.to(torch_device)
prompt_input_ids = tokenizer(prompt, return_tensors="pt").input_ids.to(torch_device)

generation = model.generate(input_ids=input_ids, prompt_input_ids=prompt_input_ids)
audio_arr = generation.cpu().float().numpy().squeeze()
Audio(audio_arr, rate=model.config.sampling_rate)

2.2 使用特定说话者生成语音

你还可以引导模型生成类似于特定说话者的语音。只需在描述中包含说话者的姓名或描述性短语以及所需的特征即可。

prompt = "Hey, how are you doing today?"
description = "Jon's voice is monotone yet slightly fast in delivery, with a very close recording that almost has no background noise."

input_ids = tokenizer(description, return_tensors="pt").input_ids.to(torch_device)
prompt_input_ids = tokenizer(prompt, return_tensors="pt").input_ids.to(torch_device)

generation = model.generate(input_ids=input_ids, prompt_input_ids=prompt_input_ids)
audio_arr = generation.cpu().float().numpy().squeeze()
Audio(audio_arr, rate=model.config.sampling_rate)

你可以从 34 个预定义的说话者姓名中进行选择,并根据你的描述定制他们的说话风格(例如 Jon、Lea、Gary、Jenna、Mike、Laura)。

提示:

  • 包括术语“非常清晰的音频”以生成最高质量的音频,以及“非常嘈杂的音频”以生成高水平的背景噪音。
  • 标点符号可用于控制生成的韵律,例如使用逗号在语音中添加小的停顿。
  • 其余语音特征(性别、语速、音调和混响)可直接通过提示进行控制。

2.3 流式语音生成

对于较长的文本输入,以块的形式流式传输音频输出。这允许你在创建生成的语音时听到它,从而提供更具互动性的体验。

def generate(text, description, play_steps_in_s=0.5):
  play_steps = int(frame_rate * play_steps_in_s)
  streamer = ParlerTTSStreamer(model, device=torch_device, play_steps=play_steps)
  # tokenization
  inputs = tokenizer(description, return_tensors="pt").to(torch_device)
  prompt = tokenizer(text, return_tensors="pt").to(torch_device)
  # create generation kwargs
  generation_kwargs = dict(
    input_ids=inputs.input_ids,
    prompt_input_ids=prompt.input_ids,
    attention_mask=inputs.attention_mask,
    prompt_attention_mask=prompt.attention_mask,
    streamer=streamer,
    do_sample=True,
    temperature=1.0,
    min_new_tokens=10,
  )
  # initialize Thread
  thread = Thread(target=model.generate, kwargs=generation_kwargs)
  thread.start()
  # iterate over chunks of audio
  for new_audio in streamer:
    if new_audio.shape[0] == 0:
      break
    yield sampling_rate, new_audio



text = "Parler-TTS is an auto-regressive transformer-based model, meaning generates audio codes (tokens) in a causal fashion."
description = "Mike's talking really fast."

chunk_size_in_s = 0.5

for (sampling_rate, audio_chunk) in generate(text, description, chunk_size_in_s):
  display(Audio(audio_chunk, rate=sampling_rate))

3、Parler-TTS 微调

本指南演示了在单说话人数据集上微调 Parler-TTS 模型的过程。有关完整的演练和代码实现,请参阅此处提供的完整笔记本。

在运行笔记本之前,请通过执行以下命令确保已安装必要的依赖项:

安装 DataSpeech:

!git clone https://github.com/huggingface/dataspeech.git
!cd dataspeech
!pip install --quiet -r ./dataspeech/requirements.txt

安装 Parler-TTS:

!git clone https://github.com/huggingface/parler-tts.git
%cd parler-tts
!pip install --quiet -e .[train]

安装其他依赖项:

!pip install --upgrade protobuf wandb==0.16.6

登录 Hugging Face:

!git config --global credential.helper store
!huggingface-cli login

3.1 创建我们的微调数据集

本节旨在创建 Jenny TTS 数据集的注释版本,以微调 Parler-TTS v0.1检查点。完整数据集可在 Hugging Face Hub 上作为 reach-vb/jenny_tts_dataset 获取,灵感来自 Data-Speech FAQ

出于演示目的,此笔记本使用6 小时子集:ylacombe/jenny-tts-6h。你可以通过 Hub 查看器收听样本。

该过程包括:1) 使用测量语音特征(说话速率、SNR、混响和语音单调性)的连续变量标注数据集,2) 将这些注释映射到描述性文本箱,以及 3) 从这些箱中创建自然语言描述。

标注过程利用 main.py 提取连续变量。

有关更详细的说明,请参阅 Data-Speech README

%cd ../dataspeech
!python main.py "ylacombe/jenny-tts-6h" \ 
  --configuration "default" \
  --text_column_name "transcription" \
  --audio_column_name "audio" \
  --cpu_num_workers 2 \
  --num_workers_per_gpu_for_pitch 2 \
  --rename_column \
  --repo_id "jenny-tts-tags-6h"

3.2  将标注映射到文本箱

为了与 Parler-TTS v0.1 检查点的训练数据保持一致,我们将对 Jenny 数据集使用相同的文本箱。使用以下命令可实现此目的:

!python ./scripts/metadata_to_text.py \
    "ylacombe/jenny-tts-tags-6h" \ 
    --repo_id "jenny-tts-tags-6h" \
    --configuration "default" \
    --cpu_num_workers 2 \
    --path_to_bin_edges "./examples/tags_to_annotations/v01_bin_edges.json" \
    --avoid_pitch_computation

此脚本通过应用模型初始训练期间使用的相同文本分箱过程来确保 Jenny 数据集与 Parler-TTS 模型之间的兼容性。

3.3 从这些文本箱创建自然语言描述

将文本箱分配给 Jenny 数据集后,下一步是根据这些特征生成自然语言描述。我们选择的方法是创建包含名字“Jenny”并描述语音特征的提示,从而得到如下提示:“Jenny 的发音非常有表现力,但发音非常慢。房间里有一些背景噪音,还有一点回声。”

这个资源密集型步骤通常需要利用 GPU。以下命令使用 Google 的 Gemma 模型 2B 版本演示了此过程,该过程在 Colab 免费 T4 上大约需要 15 分钟完成。

!python ./scripts/run_prompt_creation.py \
  --speaker_name "Jenny" \
  --is_single_speaker \
  --dataset_name "ylacombe/jenny-tts-tags-6h" \
  --output_dir "./tmp_jenny" \
  --dataset_config_name "default" \
  --model_name_or_path "google/gemma-2b-it" \
  --per_device_eval_batch_size 12 \
  --attn_implementation "sdpa" \
  --dataloader_num_workers 2 \
  --push_to_hub \
  --hub_dataset_id "jenny-tts-6h-tagged" \
  --preprocessing_num_workers 2

该命令指定要标注的数据集和配置。  model_name_or_path 参数指向适合进行快速标注的 transformers 模型,此处提供了一系列选项。

值得注意的是,标志 --speaker_name "Jenny" --is_single_speaker 明确将数据集定义为单声道说话者,并将语音标识为“Jenny”。

3.4 始微调 Parler-TTS

准备好带标注的 Jenny 数据集后,我们现在可以专注于微调 Parler-TTS 模型。Parler-TTS 库此处提供了一个方便的训练脚本,可简化此过程。

注意:脚本需要做出有关权重和偏差 (WandB) 日志记录的决定。如果你没有帐户,请选择选项 3 以禁用日志记录。否则,请启用日志记录以跟踪模型的训练进度。

以下命令启动微调过程:

%cd ../parler-tts

!accelerate launch ./training/run_parler_tts_training.py \
    --model_name_or_path "parler-tts/parler_tts_mini_v0.1" \
    --feature_extractor_name "parler-tts/dac_44khZ_8kbps" \
    --description_tokenizer_name "parler-tts/parler_tts_mini_v0.1" \
    --prompt_tokenizer_name "parler-tts/parler_tts_mini_v0.1" \
    --report_to "wandb" \
    --overwrite_output_dir true \
    --train_dataset_name "ylacombe/jenny-tts-6h" \
    --train_metadata_dataset_name "ylacombe/jenny-tts-6h-tagged" \
    --train_dataset_config_name "default" \
    --train_split_name "train" \
    --eval_dataset_name "ylacombe/jenny-tts-6h" \
    --eval_metadata_dataset_name "ylacombe/jenny-tts-6h-tagged" \
    --eval_dataset_config_name "default" \
    --eval_split_name "train" \
    --max_eval_samples 8 \
    --per_device_eval_batch_size 8 \
    --target_audio_column_name "audio" \
    --description_column_name "text_description" \
    --prompt_column_name "text" \
    --max_duration_in_seconds 20 \
    --min_duration_in_seconds 2.0 \
    --max_text_length 400 \
    --preprocessing_num_workers 2 \
    --do_train true \
    --num_train_epochs 2 \
    --gradient_accumulation_steps 18 \
    --gradient_checkpointing true \
    --per_device_train_batch_size 2 \
    --learning_rate 0.00008 \
    --adam_beta1 0.9 \
    --adam_beta2 0.99 \
    --weight_decay 0.01 \
    --lr_scheduler_type "constant_with_warmup" \
    --warmup_steps 50 \
    --logging_steps 2 \
    --freeze_text_encoder true \
    --audio_encoder_per_device_batch_size 4 \
    --dtype "float16" \
    --seed 456 \
    --output_dir "./output_dir_training/" \
    --temporary_save_to_disk "./audio_code_tmp/" \
    --save_to_disk "./tmp_dataset_audio/" \
    --dataloader_num_workers 2 \
    --do_eval \
    --predict_with_generate \
    --include_inputs_for_metrics \
    --group_by_length true

此脚本利用带标注的 Jenny 数据集和指定的参数对 Parler-TTS 模型进行微调,最终提高其性能并使其适应 Jenny 语音的特点。


原文链接:Getting Started with Parler-TTS: Tips for Fine-Tuning and Inference

汇智网翻译整理,转载请标明出处