PaddlePaddle / Parakeet

PAddle PARAllel text-to-speech toolKIT (supporting Tacotron2, Transformer TTS, FastSpeech2/FastPitch, SpeedySpeech, WaveFlow and Parallel WaveGAN)
Other
598 stars 83 forks source link

TransformerTTS + WaveFlow Pre-train synthesize 问题 #125

Closed jing-bsm closed 3 years ago

jing-bsm commented 3 years ago

我试图参照 https://github.com/PaddlePaddle/Parakeet/blob/develop/examples/tacotron2/synthesize.ipynb 写一个类似的 ipynb

在 examples/transformer_tts 下写了如下的 代码

import numpy as np
import paddle
from parakeet.utils import display
from parakeet.utils import layer_tools

import sys
sys.path.append("../..")
import examples
from parakeet.models.transformer_tts import TransformerTTS
from parakeet.frontend import EnglishCharacter
from examples.transformer_tts import config as transformer_config

# text to bin model
synthesizer_config = transformer_config.get_cfg_defaults()
synthesizer_config.merge_from_file("../../../transformer_tts_ljspeech_ckpt_0.3/config.yaml")
frontend = EnglishCharacter()
model = TransformerTTS.from_pretrained(
    frontend,synthesizer_config, "step-310000")
model.eval()
from parakeet.models.waveflow import ConditionalWaveFlow
from examples.waveflow import config as waveflow_config
vocoder_config = waveflow_config.get_cfg_defaults()
vocoder = ConditionalWaveFlow.from_pretrained(
    vocoder_config,
    "../../../waveflow_ljspeech_ckpt_0.3/step-2000000")
layer_tools.recursively_remove_weight_norm(vocoder)
vocoder.eval()

sentence = "Hello world"

text_ids = paddle.to_tensor(frontend(sentence))
text_ids = paddle.unsqueeze(text_ids, 0)  # (1, T)
with paddle.no_grad():
    outputs = model.infer(text_ids, verbose=True)

mel_output = outputs["mel_output"]

audio = vocoder.infer(paddle.transpose(outputs["mel_output"], [0, 2, 1]))

wav = audio[0].numpy()
from IPython import display as ipd
ipd.Audio(wav, rate=22050)

但输出声音只是 “嘿嘿嘿”,不知道哪位大神指导一下啊哪里错了?

iclementine commented 3 years ago

我们运行一下你的代码段,请稍候~

iclementine commented 3 years ago

原因是这里用的 frontend 是 EnglishCharacter(), 这个是我们的 tacotron 2 这个模型训练时用的 frontend, 只是把单词按照字母一个一个拆开。

但 transformer tts 训练是用了一个基于 CMUDict 中的 ARPABET 字符集的 frontend,这个需要匹配才能正常运行。所以把 EnglishCharacter 改成 English 就可以了。具体可以查看 parakeet/frontend/phonectic.py 这个文件里的内容。

亦即,把 frontend = EnglishCharacter() 改成 frontend = English(), 然后前面 import 的地方也改一下。from parakeet.frontend import EnglishCharacter 改成 from parakeet.frontend import English

jing-bsm commented 3 years ago

感谢大神的解答

问一个关于 transformer_tts spike 杂音的问题,貌似只有 transformer_tts 有这个问题,比如 doc上自己的例子

https://paddlespeech.bj.bcebos.com/Parakeet/transformer_tts_ljspeech_waveflow_samples_0.2/sentence_9.wav

在结尾的时候有时会 啪 一响, 不知道这个是训练还是什么原因产生的,有没有什么办法可以 filter 掉

iclementine commented 3 years ago

这个主要的原因是 Transformer TTS 模型的 stop condition 判断不够准确导致的。因为 Transformer TTS 的频谱合成终止是以一个分类器来判断的,我们实际训练的时候其实挺容易遇到 validation 时这个分类器的 Loss 比较大的问题。因为几百帧的音频里只有一帧是最后一帧。

论文中是说可以把正例的权重提高。但是我们把权重提高到 8,也无法遏制 validation loss 中判断最后一帧的这个分类器的 Loss 变大。

另外,我们的实现中使用了 reduction_factor, 和 tacotron1 类似,也就是解码器一步输出多帧。然后我们用某一步的输出来判断是是否是最后一步的时候,没有细分这一步里面第几帧才是确切的最后一帧,有可能会出现多了一两帧的问题。这里应该可以改进一下。比如说某一步输出了 [78, 79, 80, 81] 这几帧,我们只是判断这里面有某一帧是最后一帧,但是这4帧还是全部都包含在节结果里。其实可以更精细地计算出具体哪一帧是最后一帧,然后把后面的都丢掉。

具体代码在这里,可以做一些修改。 https://github.com/PaddlePaddle/Parakeet/blob/de61534153a86c55551464ed6761e966f3b0f449/parakeet/models/transformer_tts.py#L548