漫谈语音合成之Char2Wav模型
漫谈语音合成之Char2Wav模型
语音合成是指将文本转化成音频的过程,整个过程的难点可以用两个词语来形容:清晰度(Intelligibility)和自然度(Naturalness),清晰度是指合成的音频是否是干净的,是否可以被人听懂;而自然度是指合成的音频是否融合了情感上的色彩。传统的语音合成通常有两种做法,一种是合成式,另外一种是参数式,下面我们分别看它们各自的特点。
合成式(Concatenative TTS),这种方法需要大量的剪辑音频组成的数据库,然后根据文本内容从数据库中挑选相应的音频片段,把它们拼到一起播放即可。相信大家坐过火车,火车站的语音播报基本上都是这种简单粗暴的拼凑式语音,小编每次听到那种语音播报都觉得十分刺耳,为原本无聊的候车时光增添了更多无聊。这种方法有很多缺点,自然度差是其一,另外一个缺点是需要预先找到足够多的音频片段,不然文本中如果出现数据库中没有的字词就无法工作了。
参数式(Parametric TTS),这种方法是根据语音的基本参数来合成语音,一个参数式语音合成系统通常包含两个阶段:首先是从文本中提取语言特征,例如音节、停顿时间等,然后提取能够代表音频的特征,如倒谱、频谱、基频等。将这些语言特征和音频特征作为Vocoder的输入,然后即可产生对应文本的音频。这种方法所需要的工作量以及数据库数量相比于合成式都要少,但是,这些特征都是人为手动提取的,是基于我们人类对音频的理解,这些手动提取的特征不一定就完全适合语音合成。既然这样,为什么不把深度学习这种自动提取特征的方法引入呢?于是,深度学习就逐渐被应用到语音合成之中。
我们可以通过深度学习自动提取特征然后直接合成音频,将深度学习引入到语音合成中已有先例——DeepMind提取的wavenet模型,之前我写过这篇论文的解读,大家可以参考详述DeepMind wavenet原理及其TensorFlow实现,wavenet采取的是一种自回归生成的方法,单纯的wavenet可以基于已有的音频无监督地合成新的音频,同时,它也可以用于TTS以及语音识别,wavenet的缺点就是合成一秒钟的音频需要4秒中的生成时间,百度的Deep Voice后来对wavenet作出了改进,将其提升了400倍,另外Google最近也发表了新的论文,对wavenet的速度提升了1000倍,这些模型我们以后再详细介绍。
Char2Wav模型是由Bengio组提出来的一种基于深度学习的端对端语音合成模型,Char2Wav由两部分构成,分别是reader和neural vocoder,其中reader是一个基于注意力机制的seq2seq模型,编码器是一个双向的循环神经网络(BiRNN),使用文本或者音节作为输入,解码器是一个基于注意力机制的RNN,输出声学特征。neural vocoder是一个基于SampleRNN(SampleRNN语音合成模型)的条件抽样过程,可以直接输出音频的波形表示。不同于传统的语音合成模型,Char2Wav直接将文本作为输入就可以输出音频,Char2Wav的模型结构如下图所示。
在reader部分,作者借鉴了Chorowski提出的ARSG模型,ARSG模型基于序列X来生成序列Y,而这里的序列X就是文本或音节序列,序列Y则是声学特征序列。在ARSG的第i步,基于h生成y的步骤如下公式所示:
在neural vocoder部分,作者采用了SampleRNN来获取高质量的音频输出,SampleRNN是一个由启发性的带有不同时钟频率的循环层构成的自回归生成模型,其结构如下图所示,这种具有启发性的结构使得捕捉长程音频之间的关联性变得更加容易,作者使用了SampleRNN的条件概率版本,即把从reader输出的每一帧的声学特征附加到SampleRNN中top tier的相应状态,这样就可以根据过去的音频样本以及声学特征来一起生成新的音频样本。
在训练的时候,作者首先分别对reader和neural vocoder分别进行了预训练,将归一化之后的WORLD声学特征作为reader的目标序列和neural vocoder的输入,最后将reader和neural vocoder一起做端对端训练。作者的代码已经开源,地址是http://github.com/sotelo/parrot。
深度学习每日摘要|坚持技术,追求原创
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用JSP的标准标签库JSTL处理XML格式的数据
- (一)初识Mybatis-Plus
- org.apache.tomcat.util.scan.StandardJarScanner找不到serializer.jar的问题
- JAVA中获取当前系统时间
- 使用Supervisor管理进程
- vue 中使用threejs
- 数据库COUNT(*)、COUNT(字段)和COUNT(1)的异同
- 生成项目目录树
- 几行代码搞定智能插座控制丨云开发 × 涂鸦
- Elasticsearch Mapping是啥?
- 求水仙花数面试题 撸它
- 字典序???你是啥
- 【特征工程】时序特征挖掘的奇技淫巧
- 【Hive】Hive 的基本认识
- 《Nacos系列》之注册中心