本文结合keithito复现的Tacotron进行分析。
https://github.com/keithito/tacotron
参考资料
Tacotron: Towards End-to-End Speech Synthesis
端到端的TTS深度学习模型tacotron(中文语音合成)
TACOTRON:端到端的语音合成
Tacotron算法的系统组成
Tacotron的骨干部分是一个带attention的seq2seq模型。下图描绘了该模型架构,它包含一个encoder,一个基于attention的decoder和一个post-prosessing网络。从高层面上说,该模型接收字符的输入,输出相应的原始频谱图,然后将其提供给 Griffin-Lim 重建算法以生成语音。
Character Embedding
因为纯文本数据是没法作为深度学习输入的,所以我们首先得把文本转化为一个个对应的向量。
embedding_table = tf.get_variable(
'embedding', [len(symbols), hp.embed_depth], dtype=tf.float32,
initializer=tf.truncated_normal_initializer(stddev=0.5))
embedded_inputs = tf.nn.embedding_lookup(embedding_table, inputs) # [N, T_in, embed_depth=256]
使用标准差为stddev的截断正态分布的词嵌入层,通过训练不断的学习到语料库中的每个字的词向量。
tf.nn.embedding_lookup(embedding_table, input_ids)
就是把input_ids中给出的tensor表现成embedding_table中的形式。可以理解成创建了一个embedding_table字典,通过输入的input_ids查询字典得到embedding后的值。
encoder模块
对每个字符向量施加一组非线性变换,统称为pre-net。接着将pre-net网络的输出输入到CBHG模块中,最后从CBHG中输出的就是输入文本的一个鲁棒的序列表达。
pre-net模块
def prenet(inputs, is_training, layer_sizes, scope=None):
x = inputs
drop_rate = 0.5 if is_training else 0.0
with tf.variable_scope(scope or 'prenet'):
for i, size in enumerate(layer_sizes):
dense = tf.layers.dense(x, units=size, activation=tf.nn.relu, name='dense_%d' % (i+1))
x = tf.layers.dropout(dense