如何开始在 Ubuntu 20.04 上使用 Mozilla TTS 训练自定义语音模型?
How do I get started training a custom voice model with Mozilla TTS on Ubuntu 20.04?
我想使用我录制的音频样本在 Mozilla TTS 中创建自定义语音,但不确定如何开始。 Mozilla TTS 项目有文档和教程,但我无法将各个部分放在一起——似乎缺少一些基本信息,初学者需要知道这些信息才能开始。
我有一些问题:
- 我看到有一个用于 Mozilla TTS 的 Docker 图像,但它的文档涵盖了创建语音但没有提到训练。我可以使用 Docker 图像进行训练吗?
- 如果我不能使用 Docker 图像进行训练,我如何在我的系统上使用 Python 3 获得 Mozilla TTS 运行ning 的功能副本?我已尝试按照项目提供的命令进行操作,但出现依赖项错误、版本冲突或有关没有足够权限安装包的错误。
- 训练模型需要哪些信息?我需要什么音频格式?我看到我需要一个
metadata.csv
文件——我需要在该文件中放入什么?我在配置文件中自定义什么?
- 大多数配置都引用了一个
scale_stats.npy
文件——我该如何生成它?
- 如何运行训练?
经过大量的研究和实验,我可以分享我的经验来回答我自己的问题。
可以使用 Mozilla TTS Docker 图像进行训练吗(TL;DR:“否”)
Mozilla TTS docker 图像确实适合播放,似乎不适合用于训练。至少,即使在容器内 运行ning 一个 shell 时,我也无法进行培训。但是在找出导致 PIP 不愉快的原因之后,在 Ubuntu 中启动 Mozilla TTS 和 运行ning 的过程变得非常简单。
使用 Python 3、PIP 和虚拟环境安装 Mozilla TTS
Mozilla TTS 的文档没有提及任何关于虚拟环境的内容,但恕我直言,它确实应该提及。虚拟环境确保您机器上不同 Python-based 应用程序的依赖关系不会发生冲突。
我在 WSL 上 运行ning Ubuntu 20.04,所以 Python 3 已经安装。鉴于此,在我的 主文件夹 中,以下是我用来获取 Mozilla TTS 工作副本的命令:
sudo apt-get install espeak
git clone https://github.com/mozilla/TTS mozilla-tts
python3 -m venv mozilla-tts
cd mozilla-tts
./bin/pip install -e .
这在我的主文件夹中创建了一个名为 ~/mozilla-tts
的文件夹,其中包含 Mozilla TTS 代码。该文件夹设置为虚拟环境,这意味着只要我通过 ~/mozilla-tts/bin/python
执行 python 命令并通过 ~/mozilla-tts/bin/pip
执行 PIP,Python 将仅使用存在的包在那个虚拟环境中。这消除了在 运行ning pip
时成为 root 的需要(因为我们不影响 system-wide 包),并且它确保没有包冲突。得分!
训练模型的先决条件
为了在训练模型时获得最佳结果,您需要:
- 简短的录音(至少 100 个)是:
- 16 位单声道 PCM WAV 格式。
- 每次 1 到 10 秒。
- 采样率为 22050 Hz。
- 尽量减少背景噪音和失真。
- 开头、中间和结尾都没有长时间的沉默。
- 一个
metadata.csv
文件,它引用每个 WAV 文件并指示 WAV 文件中说出的文本。
- 为您的数据集和所选声码器(例如 Tacotron、WavGrad 等)量身定制的配置文件。
- 具有快速 CPU 的机器(最好是具有 CUDA 支持的 nVidia GPU 和至少 12 GB 的 GPU RAM;如果您的 GPU RAM 少于 8 GB,则无法有效地使用 CUDA)。
- 大量 RAM(最好至少 16 GB RAM)。
正在准备音频文件
如果您的音频源格式不同于 WAV,您将需要使用 Audacity or SoX 之类的程序将文件转换为 WAV 格式。您还应该 trim 去除扬声器中的噪音、嗯、啊和其他声音,而不是您正在训练的真正单词。
如果您的音频源不完美(即有一些背景噪音)、格式不同、采样率更高或分辨率不同(例如 24 位、32 位等) .),你可以进行一些clean-up和转换。这是一个基于来自 Mozilla TTS Discourse 论坛的 earlier script 的脚本:
from pathlib import Path
import os
import subprocess
import soundfile as sf
import pyloudnorm as pyln
import sys
src = sys.argv[1]
rnn = "/PATH/TO/rnnoise_demo"
paths = Path(src).glob("**/*.wav")
for filepath in paths:
target_filepath=Path(str(filepath).replace("original", "converted"))
target_dir=os.path.dirname(target_filepath)
if (str(filepath) == str(target_filepath)):
raise ValueError("Source and target path are identical: " + str(target_filepath))
print("From: " + str(filepath))
print("To: " + str(target_filepath))
# Stereo to Mono; upsample to 48000Hz
subprocess.run(["sox", filepath, "48k.wav", "remix", "-", "rate", "48000"])
subprocess.run(["sox", "48k.wav", "-c", "1", "-r", "48000", "-b", "16", "-e", "signed-integer", "-t", "raw", "temp.raw"]) # convert wav to raw
subprocess.run([rnn, "temp.raw", "rnn.raw"]) # apply rnnoise
subprocess.run(["sox", "-r", "48k", "-b", "16", "-e", "signed-integer", "rnn.raw", "-t", "wav", "rnn.wav"]) # convert raw back to wav
subprocess.run(["mkdir", "-p", str(target_dir)])
subprocess.run(["sox", "rnn.wav", str(target_filepath), "remix", "-", "highpass", "100", "lowpass", "7000", "rate", "22050"]) # apply high/low pass filter and change sr to 22050Hz
data, rate = sf.read(target_filepath)
# peak normalize audio to -1 dB
peak_normalized_audio = pyln.normalize.peak(data, -1.0)
# measure the loudness first
meter = pyln.Meter(rate) # create BS.1770 meter
loudness = meter.integrated_loudness(data)
# loudness normalize audio to -25 dB LUFS
loudness_normalized_audio = pyln.normalize.loudness(data, loudness, -25.0)
sf.write(target_filepath, data=loudness_normalized_audio, samplerate=22050)
print("")
要使用上面的脚本,您需要签出并构建 the RNNoise project:
sudo apt update
sudo apt-get install build-essential autoconf automake gdb git libffi-dev zlib1g-dev libssl-dev
git clone https://github.com/xiph/rnnoise.git
cd rnnoise
./autogen.sh
./configure
make
您还需要安装 SoX:
sudo apt install sox
并且,您需要通过 ./bin/pip
安装 pyloudnorm
。
然后,自定义脚本,让rnn
指向rnnoise_demo
命令的路径即可(构建RNNoise后,可以在examples
文件夹中找到)。然后,运行 脚本,传递源路径——您拥有 WAV 文件的文件夹——作为第一个命令行参数。 确保“原创”一词出现在路径中的某处。脚本会自动将转换后的文件放在相应的路径下,将original
改为converted
; 例如,如果你的源路径是/path/to/files/original
,脚本会自动将转换后的结果放入 /path/to/files/converted
.
准备元数据
Mozilla TTS 支持多种不同的数据加载器,但最常见的一种是 LJSpeech。要使用它,我们可以组织我们的数据集以遵循 LJSpeech 约定。
首先,组织您的文件,使您拥有如下结构:
- metadata.csv
- wavs/
- audio1.wav
- audio2.wav
...
- last_audio.wav
音频文件的命名似乎并不重要。但是,文件 必须 位于名为 wavs
的文件夹中。如果需要,您可以在 wavs
中使用 sub-folders。
metadata.csv
文件应采用以下格式:
audio1|line that's spoken in the first file
audio2|line that's spoken in the second file
last_audio|line that's spoken in the last file
注意:
- 没有 header 行。
- 列用竖线符号 (|) 连接在一起。
- 每个 WAV 文件应该有一行。
- WAV 文件名在第一列,没有
wavs/
文件夹前缀,也没有 .wav
后缀。
- 文字说明在 WAV 中所说的内容写在第二列中,所有数字和缩写 spelled-out.
(我确实观察到 Mozilla TTS 文档中的步骤让您随机播放元数据文件,然后将其拆分为“训练”集(metadata_train.csv
)和“验证”集(metadata_val.csv
),但是 repo 中提供的 none 示例配置实际上配置为使用这些文件。我已经提交了 an issue,因为它 confusing/counter-intuitive 适合初学者。)
正在准备 config.json
文件
您需要准备一个描述如何配置自定义 TTS 的配置文件。在准备训练、执行训练和从自定义 TTS 生成音频时,Mozilla TTS 的多个部分会使用此文件。不幸的是,虽然这个文件非常重要,但 Mozilla TTS 的文档在很大程度上掩盖了如何自定义这个文件。
首先,从 Mozilla 存储库创建 the default Tacotron config.json
file 的副本。然后,请务必至少自定义 audio.stats_path
、output_path
、phoneme_cache_path
和 datasets.path
文件。
如果您愿意,可以自定义其他参数,但默认值是一个很好的起点。例如,您可以更改 run_name
以控制包含数据集的文件夹的命名。
不要更改 datasets.name
参数(将其设置为“ljspeech”);否则你会得到与未定义数据集类型相关的奇怪错误。 数据集 name
似乎指的是所使用的 数据加载器 的类型,而不是你所谓的数据集。同样,我没有冒险更改 model
设置,因为我还不知道系统如何使用该值。
准备中scale_stats.npy
大多数训练配置依赖于一个名为 scale_stats.npy
的统计文件,该文件是根据训练集生成的。您可以使用 Mozilla TTS 存储库中的 ./TTS/bin/compute_statistics.py
脚本来生成此文件。此脚本需要您的 config.json
文件作为输入,这是一个很好的步骤,可以全面检查到目前为止一切看起来是否良好。
如果您在本教程开始时创建的 Mozilla TTS 文件夹中(调整路径以适合您的项目),您可以 运行 下面是一个命令示例:
./bin/python ./TTS/bin/compute_statistics.py --config_path /path/to/your/project/config.json --out_path /path/to/your/project/scale_stats.npy
如果成功,这将在/path/to/your/project/scale_stats.npy
下生成一个scale_stats.npy
文件。 确保 config.json
文件的 audio.stats_path
设置中的路径与此路径匹配。
训练模型
现在是关键时刻 -- 是时候开始训练您的模型了!
如果您在本教程开始时创建的 Mozilla TTS 文件夹中(调整路径以适合您的项目),下面是您可以 运行 训练 Tacotron 模型的命令示例:
./bin/python ./TTS/bin/train_tacotron.py --config_path /path/to/your/project/config.json
这个过程即使不是几天,也需要几个小时。如果您的机器支持 CUDA 并且配置正确,则该过程 运行 比您仅依靠 CPU 更快。
如果您收到与“信号错误”或“收到信号”相关的任何错误,这通常表示您的机器没有足够的内存来进行操作。你可以 run the training with less parallelism 但它会 运行 慢得多。
我想使用我录制的音频样本在 Mozilla TTS 中创建自定义语音,但不确定如何开始。 Mozilla TTS 项目有文档和教程,但我无法将各个部分放在一起——似乎缺少一些基本信息,初学者需要知道这些信息才能开始。
我有一些问题:
- 我看到有一个用于 Mozilla TTS 的 Docker 图像,但它的文档涵盖了创建语音但没有提到训练。我可以使用 Docker 图像进行训练吗?
- 如果我不能使用 Docker 图像进行训练,我如何在我的系统上使用 Python 3 获得 Mozilla TTS 运行ning 的功能副本?我已尝试按照项目提供的命令进行操作,但出现依赖项错误、版本冲突或有关没有足够权限安装包的错误。
- 训练模型需要哪些信息?我需要什么音频格式?我看到我需要一个
metadata.csv
文件——我需要在该文件中放入什么?我在配置文件中自定义什么? - 大多数配置都引用了一个
scale_stats.npy
文件——我该如何生成它? - 如何运行训练?
经过大量的研究和实验,我可以分享我的经验来回答我自己的问题。
可以使用 Mozilla TTS Docker 图像进行训练吗(TL;DR:“否”)
Mozilla TTS docker 图像确实适合播放,似乎不适合用于训练。至少,即使在容器内 运行ning 一个 shell 时,我也无法进行培训。但是在找出导致 PIP 不愉快的原因之后,在 Ubuntu 中启动 Mozilla TTS 和 运行ning 的过程变得非常简单。
使用 Python 3、PIP 和虚拟环境安装 Mozilla TTS
Mozilla TTS 的文档没有提及任何关于虚拟环境的内容,但恕我直言,它确实应该提及。虚拟环境确保您机器上不同 Python-based 应用程序的依赖关系不会发生冲突。
我在 WSL 上 运行ning Ubuntu 20.04,所以 Python 3 已经安装。鉴于此,在我的 主文件夹 中,以下是我用来获取 Mozilla TTS 工作副本的命令:
sudo apt-get install espeak
git clone https://github.com/mozilla/TTS mozilla-tts
python3 -m venv mozilla-tts
cd mozilla-tts
./bin/pip install -e .
这在我的主文件夹中创建了一个名为 ~/mozilla-tts
的文件夹,其中包含 Mozilla TTS 代码。该文件夹设置为虚拟环境,这意味着只要我通过 ~/mozilla-tts/bin/python
执行 python 命令并通过 ~/mozilla-tts/bin/pip
执行 PIP,Python 将仅使用存在的包在那个虚拟环境中。这消除了在 运行ning pip
时成为 root 的需要(因为我们不影响 system-wide 包),并且它确保没有包冲突。得分!
训练模型的先决条件
为了在训练模型时获得最佳结果,您需要:
- 简短的录音(至少 100 个)是:
- 16 位单声道 PCM WAV 格式。
- 每次 1 到 10 秒。
- 采样率为 22050 Hz。
- 尽量减少背景噪音和失真。
- 开头、中间和结尾都没有长时间的沉默。
- 一个
metadata.csv
文件,它引用每个 WAV 文件并指示 WAV 文件中说出的文本。 - 为您的数据集和所选声码器(例如 Tacotron、WavGrad 等)量身定制的配置文件。
- 具有快速 CPU 的机器(最好是具有 CUDA 支持的 nVidia GPU 和至少 12 GB 的 GPU RAM;如果您的 GPU RAM 少于 8 GB,则无法有效地使用 CUDA)。
- 大量 RAM(最好至少 16 GB RAM)。
正在准备音频文件
如果您的音频源格式不同于 WAV,您将需要使用 Audacity or SoX 之类的程序将文件转换为 WAV 格式。您还应该 trim 去除扬声器中的噪音、嗯、啊和其他声音,而不是您正在训练的真正单词。
如果您的音频源不完美(即有一些背景噪音)、格式不同、采样率更高或分辨率不同(例如 24 位、32 位等) .),你可以进行一些clean-up和转换。这是一个基于来自 Mozilla TTS Discourse 论坛的 earlier script 的脚本:
from pathlib import Path
import os
import subprocess
import soundfile as sf
import pyloudnorm as pyln
import sys
src = sys.argv[1]
rnn = "/PATH/TO/rnnoise_demo"
paths = Path(src).glob("**/*.wav")
for filepath in paths:
target_filepath=Path(str(filepath).replace("original", "converted"))
target_dir=os.path.dirname(target_filepath)
if (str(filepath) == str(target_filepath)):
raise ValueError("Source and target path are identical: " + str(target_filepath))
print("From: " + str(filepath))
print("To: " + str(target_filepath))
# Stereo to Mono; upsample to 48000Hz
subprocess.run(["sox", filepath, "48k.wav", "remix", "-", "rate", "48000"])
subprocess.run(["sox", "48k.wav", "-c", "1", "-r", "48000", "-b", "16", "-e", "signed-integer", "-t", "raw", "temp.raw"]) # convert wav to raw
subprocess.run([rnn, "temp.raw", "rnn.raw"]) # apply rnnoise
subprocess.run(["sox", "-r", "48k", "-b", "16", "-e", "signed-integer", "rnn.raw", "-t", "wav", "rnn.wav"]) # convert raw back to wav
subprocess.run(["mkdir", "-p", str(target_dir)])
subprocess.run(["sox", "rnn.wav", str(target_filepath), "remix", "-", "highpass", "100", "lowpass", "7000", "rate", "22050"]) # apply high/low pass filter and change sr to 22050Hz
data, rate = sf.read(target_filepath)
# peak normalize audio to -1 dB
peak_normalized_audio = pyln.normalize.peak(data, -1.0)
# measure the loudness first
meter = pyln.Meter(rate) # create BS.1770 meter
loudness = meter.integrated_loudness(data)
# loudness normalize audio to -25 dB LUFS
loudness_normalized_audio = pyln.normalize.loudness(data, loudness, -25.0)
sf.write(target_filepath, data=loudness_normalized_audio, samplerate=22050)
print("")
要使用上面的脚本,您需要签出并构建 the RNNoise project:
sudo apt update
sudo apt-get install build-essential autoconf automake gdb git libffi-dev zlib1g-dev libssl-dev
git clone https://github.com/xiph/rnnoise.git
cd rnnoise
./autogen.sh
./configure
make
您还需要安装 SoX:
sudo apt install sox
并且,您需要通过 ./bin/pip
安装 pyloudnorm
。
然后,自定义脚本,让rnn
指向rnnoise_demo
命令的路径即可(构建RNNoise后,可以在examples
文件夹中找到)。然后,运行 脚本,传递源路径——您拥有 WAV 文件的文件夹——作为第一个命令行参数。 确保“原创”一词出现在路径中的某处。脚本会自动将转换后的文件放在相应的路径下,将original
改为converted
; 例如,如果你的源路径是/path/to/files/original
,脚本会自动将转换后的结果放入 /path/to/files/converted
.
准备元数据
Mozilla TTS 支持多种不同的数据加载器,但最常见的一种是 LJSpeech。要使用它,我们可以组织我们的数据集以遵循 LJSpeech 约定。
首先,组织您的文件,使您拥有如下结构:
- metadata.csv
- wavs/
- audio1.wav
- audio2.wav
...
- last_audio.wav
音频文件的命名似乎并不重要。但是,文件 必须 位于名为 wavs
的文件夹中。如果需要,您可以在 wavs
中使用 sub-folders。
metadata.csv
文件应采用以下格式:
audio1|line that's spoken in the first file
audio2|line that's spoken in the second file
last_audio|line that's spoken in the last file
注意:
- 没有 header 行。
- 列用竖线符号 (|) 连接在一起。
- 每个 WAV 文件应该有一行。
- WAV 文件名在第一列,没有
wavs/
文件夹前缀,也没有.wav
后缀。 - 文字说明在 WAV 中所说的内容写在第二列中,所有数字和缩写 spelled-out.
(我确实观察到 Mozilla TTS 文档中的步骤让您随机播放元数据文件,然后将其拆分为“训练”集(metadata_train.csv
)和“验证”集(metadata_val.csv
),但是 repo 中提供的 none 示例配置实际上配置为使用这些文件。我已经提交了 an issue,因为它 confusing/counter-intuitive 适合初学者。)
正在准备 config.json
文件
您需要准备一个描述如何配置自定义 TTS 的配置文件。在准备训练、执行训练和从自定义 TTS 生成音频时,Mozilla TTS 的多个部分会使用此文件。不幸的是,虽然这个文件非常重要,但 Mozilla TTS 的文档在很大程度上掩盖了如何自定义这个文件。
首先,从 Mozilla 存储库创建 the default Tacotron config.json
file 的副本。然后,请务必至少自定义 audio.stats_path
、output_path
、phoneme_cache_path
和 datasets.path
文件。
如果您愿意,可以自定义其他参数,但默认值是一个很好的起点。例如,您可以更改 run_name
以控制包含数据集的文件夹的命名。
不要更改 datasets.name
参数(将其设置为“ljspeech”);否则你会得到与未定义数据集类型相关的奇怪错误。 数据集 name
似乎指的是所使用的 数据加载器 的类型,而不是你所谓的数据集。同样,我没有冒险更改 model
设置,因为我还不知道系统如何使用该值。
准备中scale_stats.npy
大多数训练配置依赖于一个名为 scale_stats.npy
的统计文件,该文件是根据训练集生成的。您可以使用 Mozilla TTS 存储库中的 ./TTS/bin/compute_statistics.py
脚本来生成此文件。此脚本需要您的 config.json
文件作为输入,这是一个很好的步骤,可以全面检查到目前为止一切看起来是否良好。
如果您在本教程开始时创建的 Mozilla TTS 文件夹中(调整路径以适合您的项目),您可以 运行 下面是一个命令示例:
./bin/python ./TTS/bin/compute_statistics.py --config_path /path/to/your/project/config.json --out_path /path/to/your/project/scale_stats.npy
如果成功,这将在/path/to/your/project/scale_stats.npy
下生成一个scale_stats.npy
文件。 确保 config.json
文件的 audio.stats_path
设置中的路径与此路径匹配。
训练模型
现在是关键时刻 -- 是时候开始训练您的模型了!
如果您在本教程开始时创建的 Mozilla TTS 文件夹中(调整路径以适合您的项目),下面是您可以 运行 训练 Tacotron 模型的命令示例:
./bin/python ./TTS/bin/train_tacotron.py --config_path /path/to/your/project/config.json
这个过程即使不是几天,也需要几个小时。如果您的机器支持 CUDA 并且配置正确,则该过程 运行 比您仅依靠 CPU 更快。
如果您收到与“信号错误”或“收到信号”相关的任何错误,这通常表示您的机器没有足够的内存来进行操作。你可以 run the training with less parallelism 但它会 运行 慢得多。