VITS是基于深度学习的音频技术集大成者,在HiFiGAN的基础上把音频生成应用于两类典型应用:
-
文本转语音 (Text-to-speech,TTS)
将指定文本转为语音
-
声色转化 (Voice Conversion)
将一个人的声音变为另一个人的声音
注:基于神经网络的表征学习,可以用VITS同时实现以上两个任务
1. 模型理解
可以分为 HiFiGAN部分 与 TTS 部分
-
HiFiGAN
有个编码器,输入mel谱,输出隐向量z
有个解码器(生成器),输入隐向量z,输出对应音频
-
TTS部分
这个部分是将text的语义特征融入隐向量z, 通过z实现语音 <=> 文本。
问题在于,一个文本有无限种语音可能性(1对n),但tts是需要实现1对1,即可逆,关键技术包括:
1. 流模型 (Flows) 一种可逆的生成模型,文本特征嵌入语音特征的核心模型, 它的难度在于训练,需要后两个技术。2. 单调对齐搜索(Monotonic Alignment Search,MAS)这个是一种动态规划算法,用于指导流模型训练, 但是它是单向的,即 语音 => 文本3. 时序预测器文本(Text)转为音素(Phonemes)后, 需要一个预测器实现,保证在推理阶段代替MAS。
2. 环境和参数配置
2.1 Requirements.txt
python 相关包,用pip命令安装即可,建议配置conda环境
2.2 Config文件夹
- 是一个通用的Json文件, 用于训练VITS, 官方主要有两个数据集的配置,包括:- Lj-speech (单人)和 VCTK (108人),训练多人可以实现声色转换。- 包含3个参数群- Train参数,- Data参数- Model参数
2.3 monotonic_align文件夹
用于构建文本到语音单调对齐搜索(Monotonic Alignment Search), 使用前需要用Cpython安装(Buiild)一下, 生成执行文件
3. 数据处理文件
数据集一般有两个文件夹,一个放音频,一个放text (Lj-speech 是一个csv表格)
预处理需要将下载的数据集处理为统一的格式,以方便模型训练。包括如下文件:
-
Data_utils.py
-
preprocess.py
-
text 文件夹
-
filelists文件夹
4. preprocess.py 文件
这个是脚本文件,将音频文本文件中的文本转换为音素格式文件。
-
清理功能,是对文本字符格式的转换,即将不同语言、符合的文本标准化为ASCII字符格式。
-
转音素功能,将文本转换为音素表示,音素为语音模型理解的序列。
4.1 主要功能
-
文件读取与解析:
1.该脚本通过命令行参数指定一个或多个文件列表(通常为 filelists),文件中的每一行包含了音频文件路径和对应的文本内容(例如用于语音合成的数据集)。2.通过 --text_index 参数确定文本在文件行中的位置。默认是第1列(索引1)。3.load_filepaths_and_text 函数负责从指定文件列表中加载音频文件路径和文本对。
-
文本清理
-
脚本会对每一条文本应用一个或多个清理器进行处理,清理器由 --text_cleaners 参数指定,默认使用 english_cleaners2。
-
文本清理的主要目的是移除不需要的符号、空格或其他影响模型训练的字符,保证文本干净且适合输入到模型中。
-
文本清理由 text._clean_text 函数完成,该函数根据传入的清理器(例如 english_cleaners2)来处理英文文本转音素过程。
-
-
生成新的文件
- 处理后的文本会被重新写入文件,新的文件名是原文件名加上一个后缀(通过 --out_extension 参数指定,默认是 .cleaned)。
2.每一行文本与音频文件路径仍保持对应关系,确保不会因为清理过程导致文件与文本的配对出错。
4.2 参数解析
--out_extension:用于指定生成新文件的扩展名后缀,默认为 "cleaned",也就是生成的新文件名会以 .<out_extension> 作为后缀。--text_index:用于指定文本在文件中的位置,默认为第1列(索引1),通常这是音频文件路径与文本配对数据集中的文本部分。--filelists:输入的文件列表,包含音频文件路径和文本配对,默认处理两个文件:"filelists/ljs_audio_text_val_filelist.txt" 和 "filelists/ljs_audio_text_test_filelist.txt"。--text_cleaners:指定要使用的文本清理器,默认为 ["english_cleaners2"],可以通过传入不同的清理器实现不同的文本清理规则。
4.3具体流程
1. 解析参数:通过 argparse 模块解析命令行传入的参数。
2. 加载文件列表:使用 load_filepaths_and_text 从文件中加载音频路径和文本对。
3. 清理文本:对每一条文本应用指定的清理器(例如 english_cleaners2)进行处理,生成清理后的音素文本。
4. 写入新文件:将处理后的内容按照原格式写入新文件,文件名会添加 .cleaned 后缀。
5. Text 文件夹
用于文本预处理,包含 symbols.py 和 cleaners.py 和两个文件,通过自带的__init__.py文件是整合两个文件功能。
-
symbols.py
将文本映射为符号的索引数字表示。映射简化了模型的输入处理,使模型能够更容易地处理和生成语音。
-
cleaners.py
将文本的每个部分音素化,帮助在文本和音频对齐。
-
音素
根据发音特性、应力、位置等因素会有不同的音素ID。即使是同一个字母,如果发音或应力不同,也会得到不同的ID。
-
应力
有多种形式(如重读、次重读、无重读等),这会导致同样的字母(由于其所处的位置和应力不同,而被映射到不同的音素。
5.1 Symbols.py
符号集(symbols)文件,这个符号集包括了文本预处理和表示所需的所有可能字符,并为每个字符分配了唯一的标识符。
symbos包括填充字符、标点符号、字母和国际音标字符等特殊符号, 即将文本中的各种特殊字符映射到符号集合中。
-
符号定义:
1._pad: 用于填充的符号,通常在处理不等长的序列时使用。
2._punctuation: 标点符号的集合,包括常见的句号、逗号、问号等。
3._letters: 大写和小写字母的集合,涵盖了英语字母表。
4._letters_ipa: 国际音标(IPA)字符的集合,用于表示不同的发音符号。 -
符号列表:
将所有的符号合并成一个列表
1._pad 被放在列表的开头,用于填充。2._punctuation 包含的所有标点符号。3._letters 包含的所有字母(大写和小写)。4._letters_ipa 包含的所有国际音标字符。
5.2 Cleaners.py
通过多个步骤将输入文本标准化,适合TTS模型处理。每个清理器函数对文本进行特定的转换,如缩写扩展、音素化、标点符号保留等。
-
依赖库
-
re:正则表达式库,用于匹配和替换文本中的模式。
-
unidecode:一个将非ASCII字符转换为其ASCII等价物的库。适用于将文本标准化为仅包含基本字符。
-
phonemize:用于将文本转换为音素表示的库(将文字转化为语音模型理解的音素序列)。
-
-
正则表达式和缩写映射
-
_whitespace_re:匹配一个或多个空白字符的正则表达式,用于压缩空白符号。
-
_abbreviations:一组常见的英文缩写及其完整形式的映射列表。通过这些规则,像"Mr." 会被展开为 “mister”。
-
-
主要函数
1.expand_abbreviations(text)
- 作用:展开缩写,将文本中的常见缩写替换为它们的完整形式。
- 实现:通过遍历 _abbreviations 列表,使用 re.sub(正则表达式替换)将缩写替换为完整单词。
2.expand_numbers(text):
- 作用:将数字展开为文字形式,如 “5” 转换为 “five”。
- 注意:这个函数实际调用的 normalize_numbers 未定义,因此在实际使用时需要实现这个功能。
3.lowercase(text):
- 作用:将文本转换为小写。
4.collapse_whitespace(text):
- 作用:通过正则表达式 _whitespace_re 将多个空白字符压缩为一个空格,确保文本的格式化一致。
5.convert_to_ascii(text):
- 作用:使用 unidecode 将文本中的非ASCII字符转换为其对应的ASCII字符。主要用于文本的转码,使其更容易处理和标准化。
-
清理函数basic_cleaners
不转码和音素化的情况。主要用于快速标准化文本,不进行语言的复杂处理。
1. 将文本转换为小写。
2. 压缩空白字符。
3. 不转码和音素化的情况。主要用于快速标准化文本,不进行语言的复杂处理。
- 清理函数transliteration_cleaners
适用于非英语文本,将文本标准化为ASCII字符,可以处理带有特殊字符的语言(如带有重音符号的法语)。
1.将文本转化为ASCII字符(通过 unidecode)。
2. 将文本转换为小写。
3.压缩空白字符。
-
清理函数english_cleaners
适用于处理英文文本,将其转换为音素表示。这种处理方式特别适合语音合成模型,因为音素表示能更好地指导模型生成正确的发音。
1.将文本转化为ASCII字符。
2.将文本转换为小写。
3.展开缩写。
4.使用 phonemize 将文本转换为音素(language='en-us’表示使用美式英语发音)。
5.压缩空白字符。
-
清理函数 english_cleaners2
和 english_cleaners 的处理步骤相同,适用于需要更细致的音素表示,特别是当标点和音调在生成语音时起重要作用的场景, 不同点如下。
1. 保留标点符号。2. 包含重音标记(stress),使生成的音素包含音调信息。
5.3 init.py
整合文本到音素 (Text-to-Phoneme)的过程, 通过函数 text_to_sequence 实现,
-
先转换通常用于将文本数据转换为音素
-
再将转换为一个由整数(ID)组成的序列,不同ID对应于文本中的不同字符。
6. Data_utils.py
包括5个类,前2个处理Lj-Speech, 后2个处理VCTK, 最后1个分布式分割处理数据
6.1 TextAudioLoader
继承了torch.utils.data.Dataset类,除构造函数外,还需实现默认函数:1. __getitem__ 函数定义了如何根据索引来获取单个样本(音频和文本对)。2. __len__ 函数返回数据集的总长度。
-
类功能:
1. 加载音频和文本对:从给定的文件路径中加载音频文件和相应的文本。2.文本归一化:将文本标准化并转换为整数序列(通常是字符或音素的 ID)。3.计算音频的谱图:通过音频文件计算对应的 Mel 时频谱图,用于模型输入。
-
使用步骤:
1. 准备文件列表2.定义超参数(hparams):包含数据预处理和模型相关参数的对象,像音频采样率、滤波器长度、窗口长度等都3.创建 TextAudioLoader
dataset = TextAudioLoader(audiopaths_and_text=‘path/to/audiopaths_and_text.txt’, hparams=hparams)
4.使用 DataLoader 进行批处理
创建 dataset 实例对象后,可以将其传递给 torch.utils.data.DataLoader,以便在训练模型时自动加载和批处理数据。
dataloader = torch.utils.data.DataLoader(dataset, batch_size=32, shuffle=True, num_workers=4)
直接遍历 DataLoader 获取批次的数据:
for batch in dataloader:text, spec, wav = batch # 在这里使用 text, spec, wav 进行训练或推理
-
核心函数:
-
get_audio_text_pair(self, audiopath_and_text):获取指定路径下的音频和文本,返回处理后的文本、时频谱图和音频波形。
-
get_audio(self, filename):加载音频文件,并计算其 Mel 时频谱图。如果已缓存时频谱图文件(.spec.pt),则直接加载缓存的时频谱图。
-
get_text(self, text):处理文本,将其转换为序列化的整数(文本 ID)。支持是否添加空白符和是否使用清洗后的文本。
-
6.2 TextAudioCollate
用于数据批处理(batching),为模型输入的文本、时频谱图和音频波形做统一的零填充,并根据频谱图长度进行排序,确保数据可以批量化地输入到模型中进行训练。
-
类功能:
- Zero-padding:对文本、时频谱图和音频波形进行零填充,使得批次中的所有样本具有相同的长度。
2.按序列长度排序:在整理批次时,将批次内的数据根据时频谱图长度从长到短排序。这通常用于提高模型的训练效率,尤其是在 RNN 或 Transformer 等依赖输入长度的模型中,长样本优先处理可以减少不必要的计算开销。
-
数据处理过程:
1.ids_sorted_decreasing:通过时频谱图的长度对批次内的样本进行降序排序。这样可以确保较长的样本在批次前面,便于之后的零填充处理。
2.获取当前批次中最大长度的文本、时频谱图和音频波形,确保后续的零填充能够对齐到最大长度。
3.为文本、时频谱图和音频波形分别初始化填充张量 text_padded, spec_padded, wav_padded,它们的维度对应于批次大小和最大长度。
3.遍历排序后的批次样本,将每个样本的文本、时频谱图和音频波形按顺序填入相应的张量中。对于长度不够的部分,自动填充零。
4.默认情况下返回零填充后的文本、频谱图、音频波形以及它们的长度,也可返回排序 ID。
(text_padded, text_lengths, spec_padded, spec_lengths, wav_padded, wav_lengths,ids_sorted_decreasing)
6.3 TextAudioSpeekerLoader
1.这个类与 TextAudioLoader 类似,区别在于它额外引入了说话人 ID,以便处理包含多个说话人的数据集。
- 输入音频、说话人 ID 和文本对。
格式从(audio_path, text),变为 (audio_path, speaker_id, text)
- 输出即返回格式为由(text, spec, wav) 变为 (text, spec, wav, sid)
- TextAudioSpeekerCollate
与TextAudioCollate,多了一个ID号区别不同说话人
6.4 DistributedBuckerSampler
是一个用于分布式数据采样的类,它设计了一个桶(Bucker),将一个音频-文本对分为多个段(buckets),确保每个批次中的样本长度相同。
优点:提高训练时的计算效率和稳定性,数据分割为桶后,减少补零即填充操作(padding)。
缺点:单个数据的量变少,数据划分的个数变多,导致训练迭代同样次数时,数据学习的总量变少,训练时间变长。
注:这个类对单GPU训练没用,可以屏蔽掉这部分。
7. filelists文件夹
用于组织 文本-音频 对的文件, 即text-audio pair,其中音频是记录了音频的路径,后面通过函数加载对应路径的音频,转为mel时频谱
- Lj-Speech
1行一个数据样本,用’|’ 分割 音频路径 和 文本字符串
- VCTK
多了一个speaker id,用于区分是哪一个人
音素版如下:
末尾为 .cleaned文件
-
Lj-Speech
-
VCTK
Reference
- https://github.com/jaywalnut310/vits