手把手教你打造端到端语音合成系统
参考项目(将这些项目改成中文的语音合成)
- keithito/tacotron
- Kyubyong/tacotron
- Rayhane-mamah/Tacotron-2
- NVIDIA/tacotron2
一些相关组件的参考项目(欢迎补充)
Github 项目推荐 | 一个简单的英文字形转音素的 Python 模块
自然语言处理_The CMU Pronouncing Dictionary(卡耐基梅隆大学发音词典)
1.传统语音合成技术简介
语音合成,通常又称文语转换(Text To Speech,TTS),是一种可以将任意输入文本转换成相应语音的技术,是人机语音交互中不可或缺的模块之一。如果说语音识别技术是为了让机器能够“听懂”人说话,那么语音合成技术则让机器能够跟人“说话”。无论是在地图导航、语音助手、教育、娱乐等软件应用,还是在智能音箱、家电、机器人等硬件设备中,都有语音合成技术的身影。 如图 1 所示,语音合成系统通常包含前端和后端两个模块。 前端模块主要是对输入文本进行分析,提取后端模块所需要的语言学信息。对中文合成系统来说,前端模块一般包含文本正则化、分词、词性预测、多音字消歧、韵律预测等子模块。后端模块根据前端分析结果,通过一定的方法生成语音波形。后端模块一般分为基于统计参数建模的语音合成(Statistical Parameter Speech Synthesis,SPSS,以下简称参数合成),以及基于单元挑选和波形拼接的语音合成(以下简称拼接合成)两条技术主线。
图1 语音合成系统基本框架
传统TTS是基于拼接和参数合成技术,效果上同真人语音的自然度尚有一定差距,效果已经达到上限,在实现上也依赖于复杂流水线,比如以文本分析为前端的语言模型、语音持续时间模型、声学特征预测模型、将频谱恢复成时域波形的声码器(vocoder)。这些组件都是基于大量领域专业知识,设计上很艰难,需要投入大量工程努力,对于手头资源有限的中小型玩家来说,这种“高大上”的技术似乎有些玩不起。
2.端到端语音合成的简介
为了解决传统语音合成的弊端促使了端到端语音合成的出现,研究者希望能够使合成系统能够尽量的简化,减少人工干预和对语言学相关背景知识的要求。近年来基于神经网络架构的深度学习方法崛起,使得原本在传统专业领域门槛极高的TTS应用上更接地气。端到端合成系统直接输入文本或者注音字符,系统输出音频波形。前端模块得到极大简化,甚至可以直接省略掉。端到端合成系统相比于传统语音合成,降低了对语言学知识的要求,可以方便的在不同语种上复制,批量实现几十种甚至更多语种的合成系统。借助于深度学习模型的强表达能力,端到端语音合成系统表现出令人惊艳的合成效果和强大丰富的发音风格与韵律表现力。
2017年初,Google 提出了一种新的端到端的语音合成系统——Tacotron。Tacotron是一种端到端的TTS生成模型。所谓“端到端”就是直接从字符文本合成语音,打破了各个传统组件之间的壁垒,使得我们可以从<文本,声谱>配对的数据集上,完全随机从头开始训练。从Tacotron的论文中我们可以看到,Tacotron模型的合成效果是优于要传统方法的,如图2。
图2 平均意见得分(MOS)测试结果
论文地址: Tacotron: Towards End-to-End Speech Synthesis
注明:Tacotron和Tacotron2师出同门,总体思路是一样的,以后再具体讲解它们的结构,这里不展开
端到端的语音合成系统整体技术架构选型如图3所示,红色为今天所使用的技术栈。
图3 端到端的语音合成系统技术栈
3.基于Tacotron普通话语音合成的实践
3.1 项目运行所需的软硬件环境
- 包括NVIDIA GTX系列显卡及其驱动
- 使用python3以及安装好Tensorflow模块
- 下载训练普通话语料库
- THCHS-30上下载6.4G大小的THCHS-30,这是由清华大学开放的汉语普通话语料,许可证为Apache License v2.0。
- 其他普通话训练语料库
- Aishell-1
- 标贝数据集
- 几个最新免费开源的中文语音数据集
- git clone Tacotron的源代码.
- 普通话Tacotron的源代码
3.2 开始实践
- 先clone源代码到本地~/tacotron,然后解压THCHS-30数据集到根目录下,如下所示:
# 1.创建名为tacotron的python3.6虚拟环境(建议)
> conda create -n tacotron python=3.6
# 2.clone源代码
> git clone https://github.com/X-CCS/mandarin_tacotron_GL
# 3.解压THCHS-30数据集到根目录下
> tar zxvf data_thchs30.tgz -C ~/tacotron
# 4.安装所需的环境文件
> pip install -r requirements.txt
> pip install -r requirements.txt -i https://pypi.doubanio.com/simpl # 使用豆瓣源安装更快
注意,~/tacotron是默认的路径,之后运行Python程序会直接把~/tacotron作为根目录,如果你的项目根目录不一样,那么你必须修改程序的默认路径参数,否则会出现运行错误。
- 我们可以深入到:~/tacotron/data_thchs30/data里面去观摩一下。
根据所需数据集更改datasets/thchs30.py
这一步如果遇到”FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; “错误,请参考以下内容。
- 解决方法:
- 成功解决FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `ar。
- 解决方案:更新安装包到最新,例如:
pip install --upgrade (scipy | tqdm) -i https://pypi.doubanio.com/simple
- 其中缀为“wav”是语音文件,采样率16KHz,样本宽度16-bit,单声道,内容是时长为10s左右的一段汉语。
- 后缀为“trn”文件为文本标注(transcript),不同语言有着不同的标注方法,比如英语就可以直接用26个字母加上标点符号作为标注,也就是直接使用英文内容本身;韩语由它自己一套字母表,每个字母可以使用Unicode代码作为标注字符;而汉字本身有2~3万个,穷举的话太多,还有很多同音字,所以我们使用汉语拼音作为字符标注是一种可行方案(在此向汉语拼音之父周有光表示敬意)。
- 比如有这么一句:
绿 是 阳春 烟 景 大块 文章 的 底色 四月 的 林 峦 更是 绿 得 鲜活 秀媚 诗意 盎然
- 用汉语拼音标注为:
lv4 shi4 yang2 chun1 yan1 jing3 da4 kuai4 wen2 zhang1 de5 di3 se4 si4 yue4 de5 lin2 luan2 geng4 shi4 lv4 de5 xian1 huo2 xiu4 mei4 shi1 yi4 ang4 ran2
- 题外话:粤语标注可以参考 python-jyutping,例如:
'广东话'-> ['gwong2', 'dung1', 'waa6']
注意到除了拉丁字母的拼音,还有1~5个阿拉伯数字,表示声调(四种声调加上轻声)。 也可以使用 音素(声母+韵母)为单元标注:
l v4 sh ix4 ii iang2 ch un1 ii ian1 j ing3 d a4 k uai4 uu un2 zh ang1 d e5 d i3 s e4 s iy4 vv ve4 d e5 l in2 l uan2 g eng4 sh ix4 l v4 d e5 x ian1 h uo2 x iu4 m ei4 sh ix1 ii i4 aa ang4 r an2
根据实验结果要指出,如果以字符为单位[a-z1-5],其实上述两种标注方法没有本质区别,故我们只要使用汉语拼音标注方案即可。
音频分析所使用的工具为Adobe Audition,如下:
思考:如何实现中英文混合的合成语音出来?
- 改模型结构:多个embedding融合。
- 数据集融合:LJSpeech1.1 + 标贝数据集转换为国际音标
上叙说明只是自己的猜想,后续会有实验说明
- 接下来进入实际操作阶段。在根目录下运行如下命令,对训练语料精心预处理:
> python3 preprocess.py --dataset thchs30
> # 如果数据集放在其他位置:
> python3 preprocess.py --base_dir (your file path) --dataset thchs30
预处理命令成功运行的效果
这条命令会在根目录下生成training目录,里面存放了每个音频文件的mel频谱和线性频谱(通过短时傅里叶变换STFT而得),后缀为"npy"的文件,用numpy库加载即可得到多个narray数组(可以视为多个特征向量组成的多维矩阵),用作语音的声学特征提取。除此之外还有个train.txt文件,里面基本上就是csv的格式将拼音标注同每个文件的声谱对应起来。
training文件
打开.npy文件
- 有了<文本,声谱>配对数据集形式后,我们可以训练了,输入以下命令行:
> nohup python3 train.py --name thchs30 > output.out &
训练命令成功运行的效果
我们使用了nohup命令来屏蔽一切中断信号,同时将Python进程置于后台,这是由于训练过程十分漫长(一般收敛需要10个小时,得到好的效果需要2天),免得网络中断或者终端断开导致Python进程被杀死。训练过程中的输出将会保存在logs-thchs30目录下,可能是这样的:
以上是92K次迭代后保存下来的模型和alignment图,顺便说一下我们不需要关注step-92000-align.wav这个音频文件,这并不是通过模型预测的实际效果,只是在训练中使用了teacher forcing方法,不代表evaluation效果,可以不去管它。 如何判断训练是否达到预期呢?个人经验有两个:一看学习是否收敛;二看损失(loss)低于某个值。由于Tacotron模型本质上是基于编码器解码器模式的seqtoseq模型,所以学习是否收敛可以从编码器序列和解码器序列是否对齐(alignment)判断。
step=140000,loss=0.08663
step=92000,loss=0.07889
这里放了两张alignment图对比,上图训练了140K次迭代,可以看到没有出现对齐,说明没有收敛。可能的原因很多,比如数据集质量不好,标注不正确等等。下图是92K次迭代,可以看到对齐情况良好,表明基本上可以通过文本来合成出有效的语音。这里要指出,所谓对齐并不是一定要笔直的斜线,它只是代表编码器序列(文本)和解码器序列(声谱)是否对应起来,而且像素点越亮,效果越好。 第二个判断点是loss值,越小表明越接近地真值(ground truth),当然必须在收敛的前提下,loss会趋于稳定。在实际训练中有可能出现loss值很低,但是仍然没出现alignment的情况,这是是无法合成语音的。 当我们从训练日志上看到,loss值低于0.07的时候,基本表示学习收敛并且效果稳定了。可以杀掉后台Python进程,别担心,logs-thchs30目录下已经保存了之前训练过程中产生的模型,你可以从任意时刻生成模型随时恢复继续训练,比如我们需要从92K次迭代生成的模型基础上继续训练,命令行如下:
> nohup python3 train.py --name thchs30 --restore_step 92000 >> output.out &
在训练过程中我们可以使用Tensorboard观察训练的过程,参考以下命令:
> cd logs-thchs30
> tensorboard --logdir ./
好了,现在终于到了检验我们录音效果的时刻了!不过我们无法直接输入汉字文本,而是拼音标注,好在有开源项目 python-pinyin帮我们搞定. 比如我们想合成一句“每个内容生产者都可以很方便地实现自我价值,更多的人有了微创业的机会。”我们使用python-pinyin输出的拼音标注拷贝到eval.py里,输入命令行:
> python3 eval.py --checkpoint logs-thchs30/model.ckpt-133000
一段时间后,就会在logs-thchs30目录下生成了eval-133000-0.wav,这就是我们想要的结果,一起来听听看吧~
播放音频
当然我们可以使用web server方式检验我们的合成的效果:
> python demo_server.py --checkpoint logs-thchs30/model.ckpt-10000