FastSpeech复现笔记

FastSpeech复现笔记

这几天把FastSpeech这篇论文进行了实现,地址为:

xcmyz/FastSpeechgithub.com图标

这个实现有以下几个需要注意的地方:

  1. 将decoder的输出接上一个线性层,变成80维的mel声谱图,在加上一个postnet(与Tacotron2一致),生成新的mel声谱图;
  2. FFTBlock内部的Conv1D的padding size为1,保证前后输入输出长度一致;
  3. 原论文使用了Transformer-TTS来提供alignment target,因为我没有训练好的Transformer-TTS model,我使用了英伟达发表的Tacotron2 model来提供alignment;
  4. 提供两种训练模式,一种是边进行Tacotron2计算得到alignment边训练,一种是先将数据集中所有的alignment计算完成进行保存,再进行训练。前者Tacotron2的计算会严重拖慢训练的速度,后者计算整个数据集的alignment的耗时较长(RTX2080ti用时约7小时);
  5. 支持自定义alignment,需要重写alignment.py文件;
  6. 由于Tacotron2得到的声谱图和ground truth存在差异,在计算loss阶段依照最短的长度进行裁取之后计算loss;
  7. 该实现没有使用Duration Predictor的输出来扩增encoder output,而是依照alignment target来扩增encoder output;
  8. LengthRegulator的最后一个线性层的output经过ReLU激活函数(为了去掉负值)做为该模块的输出,在inference阶段,LengthRegulator的output经过torch.exp减一后,做为encoder output扩增的倍数,training阶段,target加一后经过torch.log后与LengthRegulator的output做loss;
  9. 支持Data Parallel;
  10. train_accelerated.py 和 data_utils_accelerated.py相互配合,负责将数据预读入显存中,减少模型加载数据的时间;
  11. 基于Pytorch 1.1.0实现,使用LJSpeech-1.1数据集进行训练。

实验过程中也发现了几个问题:

  1. 对encoder output进行扩增时,由于没有真实的target,就需要依照另一个训练好的model的alignment来进行扩增,而这个model的准确率会存在问题,对performance会产生负面影响;
  2. 百度的ParallelNet直接依照经验将一定数量的position embedding做为的decoder的input,而这个数量就是encoder output的长度乘以常数,这样的设计方式有可能会取得更好的效果(没有受到其他model的影响),但这种设计使得decoder的input与target信息相差比较大。

贴出model的整体结构代码:

class FastSpeech(nn.Module):
    """ FastSpeech """

    def __init__(self):
        super(FastSpeech, self).__init__()

        self.encoder = Encoder()
        self.length_regulator = LengthRegulator()
        self.decoder = Decoder()

        self.mel_linear = Linear(hp.decoder_output_size, hp.num_mels)
        self.postnet = PostNet()

    def forward(self, src_seq, src_pos, mel_max_length=None, length_target=None, alpha=1.0):
        encoder_output, encoder_mask = self.encoder(src_seq, src_pos)

        if self.training:
            length_regulator_output, decoder_pos, duration_predictor_output = self.length_regulator(
                encoder_output,
                encoder_mask,
                length_target,
                alpha,
                mel_max_length)
            decoder_output = self.decoder(length_regulator_output, decoder_pos)

            mel_output = self.mel_linear(decoder_output)
            mel_output_postnet = self.postnet(mel_output) + mel_output

            return mel_output, mel_output_postnet, duration_predictor_output
        else:
            length_regulator_output, decoder_pos = self.length_regulator(
                encoder_output, encoder_mask, alpha=alpha)

            decoder_output = self.decoder(length_regulator_output, decoder_pos)

            mel_output = self.mel_linear(decoder_output)
            mel_output_postnet = self.postnet(mel_output) + mel_output

            return mel_output, mel_output_postnet

Non-AutoRegressive的TTS model仍然具有很大的发展空间。


Update(19/10/23):

  1. Fix bugs in alignment;
  2. Fix bugs in transformer;
  3. Fix bugs in LengthRegulator;
  4. Change the way to process audio;
  5. Use waveglow to synthesize.
编辑于 2019-10-24

文章被以下专栏收录