文章目录
- 1 概述
- 2 模型架构
- 3 模块解析
- 3.1 获取梅尔频谱
- 3.2 speaker encoder
- 3.3 AutoVC
- 3.4 Vocoder
- 4 关键部分
- 参考资料
1 概述
voice conversion这个任务的目标是输入两个音频,其输入是两段音频,一段音频称为content_audio,另一段称为speaker_audio。模型将抽取content_audio中的说话内容特征和speaker_audio中的语者特征,将两者结合,输出用speaker_audio中的说话人的声音说content_audio中的内容的音频。
这个任务的模型一般会有两个问题:
- 需要成对的数据,即需要多个人说同一句话的数据
- 无法用在没有在训练数据中出现过的人声上
AutoVC成功解决了这两个问题,也就是它不需要成对的数据,同时也可以做到zero-shot conversion。
官方给出的demo可见https://auspicious3000.github.io/autovc-demo/。效果还是很不错的,但是在中文语音上的表现就很差了。要在中文上做,就需要在中文数据集上重新训练了。中文的训练数据还是比较好找的,只要是知道每一句话是谁说的数据集都可以,比如ASR的数据集就都是可以拿来用的。
2 模型架构
voice conversion的整体流程如下图2-1所示。
首先会对输入的content_wav和speaker_wav抽取梅尔频谱,接着将抽取得到的speaker_mel过一个speaker_embedding模型,抽取语者的特征,然后将语者特征和content_mel一起输入到AutoVC当中进行融合,得到融合之后的梅尔频谱merged_mel,最后把merge_mel过vocoder就得到了最终的输出音频。
这里用紫色方框框出的是需要训练的部分,用土色方框框出的是可以更换的部分。
3 模块解析
3.1 获取梅尔频谱
这个模块的输入时声音信号,输出是声音信号的梅尔频谱,一般是80维的。
不同的模型在抽取梅尔频谱时,参数会有所不同,而这里的梅尔频谱也影响了输入vocoder的梅尔频谱。因此在使用不同的模型拼成整个流程时,需要对梅尔频谱的处理做统一,这个在实现的时候是很重要的一步。否则训练好的模型,和后面的模型接不上了,就挺麻烦的。
3.2 speaker encoder
这个部分是将音频中语者的特征给抽取出来,输入是梅尔频谱,输出是一个256维的特征。
所谓语者的特征也就是和内容无关,只和说话人有关的特征。这个模型训练时候的目标是使得同一个人说不同的话输出相同的256维的向量,使得不同的人说同一句话输出不同的256维的向量。
这个模型是可以使用预训练好的模型的,AutoVC中使用的是在VoxCeleb1和Librispeech上预训练好的Dvector,共3549个语者。
训练之前,把每个语者说的所有话,分别过一下speaker encoder,并把这些embedding取一个平均,作为这个语者的speaker embedding。
预测的时候,把输入的speaker_mel过一下speaker encoder,将输出的特征作为语者的speaker embedding。
这个speaker embedding是一个很重要的特征,如果这个特征不够好的话,会导致训练的AutoVC训练的也不够好。
我们也可以在中文的语料上重新训练一下这个模型。也可以拿别人在中文语料上预训练过的模型,比如MockingBird。
3.3 AutoVC
AutoVC这个模块才是这篇文章的重点,它由一个content encoder(EcE_cEc),一个speaker encoder(EsE_sEs)和decoder组成。这里的EsE_sEs就是3.2中的speaker encoder,是预训练好的,所以用灰色来表示。其推理时的示意图如下图3-1(a)所示,其训练时的示意图如下图3-1(b)所示。
在图3-1(a)表示了推理时候的流程图,X1X_1X1为content_audio的mel-spectrogram,Z1Z_1Z1为X1X_1X1中的内容特征,U1U_1U1为X1X_1X1中的语者特征,EcE_cEc表示抽取内容特征的content encoder,C1C_1C1是抽取出来的内容特征;X2X_2X2为speaker_audio的mel-spectrogram,Z2Z_2Z2为X2X_2X2中的内容特征,U2U_2U2为X2X_2X2中的语者特征,表EsE_sEs示抽取语者特征的speaker encoder,S2S_2S2是抽取出来的语者特征;DDD表示融合特征的decoder,X^1→2\hat{X}_{1 \rightarrow 2}X^1→2表示最终转换后的mel-spectrogram。
在图3-1(b)表示了训练时候的流程图,训练时,我们没有成对的数据,也就是没有两个人说同一句话的数据,所以没有了S2S_2S2,只有S1S_1S1。这个S1S_1S1并不是单个X1X_1X1经过EsE_sEs得到的,而是说X1X_1X1这句话的这个人说的所有的话,分别经过EsE_sEs之后,取平均得到的,也就是在训练之前就已经确定了的。X^1→1\hat{X}_{1 \rightarrow 1}X^1→1表示自重建之后的梅尔频谱,我们希望它与X1X_1X1越接近越好。
作者在decoder(DDD)这里还加了一个postnetwork,这个网络起到一个修正的作用,其输入是X^1→2\hat{X}_{1 \rightarrow 2}X^1→2,输出是R^1→2\hat{R}_{1 \rightarrow 2}R^1→2,看这个用来表示的符号也可以猜出来,是残差的意思。有了残差之后,最终的结果为
X^final1→2=X^1→2+R^1→2(3-1)\hat{X}_{final \ 1 \rightarrow 2} = \hat{X}_{1 \rightarrow 2} + \hat{R}_{1 \rightarrow 2} \tag{3-1} X^final 1→2=X^1→2+R^1→2(3-1)
训练时的Loss由三部分构成
自重建损失其一:
Lrecon=E[∣∣X^1→1−X1∣∣22](3-2)L_{recon} = E[|| \hat{X}_{1 \rightarrow 1} - X_1 ||^2_2] \tag{3-2} Lrecon=E[∣∣X^1→1−X1∣∣22](3-2)
自重建损失其二:
Lrecon0=E[∣∣X^final1→1−X1∣∣22](3-3)L_{recon0} = E[|| \hat{X}_{final \ 1 \rightarrow 1} - X_1 ||^2_2] \tag{3-3} Lrecon0=E[∣∣X^final 1→1−X1∣∣22](3-3)
内容损失:
Lcontent=E[∣∣Ec(X^final1→1)−C1∣∣1](3-4)L_{content} = E[|| E_c(\hat{X}_{final \ 1 \rightarrow 1}) - C_1 ||_1] \tag{3-4} Lcontent=E[∣∣Ec(X^final 1→1)−C1∣∣1](3-4)
总的损失为
L=Lrecon+μLrecon0+λLcontent(3-5)L = L_{recon} + \mu L_{recon0} + \lambda L_{content} \tag{3-5} L=Lrecon+μLrecon0+λLcontent(3-5)
其中,μ\muμ和λ\lambdaλ时用来调整不同loss之间权重的超参数。这些loss都是保证了模型的自重建能力。
3.4 Vocoder
Vocoder的作用是将梅尔频谱还原回音频信号,正常情况下,这个模型不用替换。原文中使用的是wavenet,但是wavenet的速度太慢了,一个5秒的音频要15分钟才能跑出来,这根本没法用。
开源之后,作者又提供了训练好的hifi-gan作为vocoder,hifi-gan就比wavenet快很多了,效果也是不错的。只是会有一些电音。这个也可以自己finue-tune一下,不过要训练hifi-gan的话,get_mel这里也要注意一致性的问题。
4 关键部分
有人可能会质疑,为什么这样训练出来的C1C_1C1就是内容的特征,就算S1S_1S1是干净的语者的特征,C1C_1C1里就不会也参杂一点语者的特征吗?
原文中也对这个问题进行了说明,列了一些假设。大前提是S1S_1S1是干净的语者特征。
我这里不求甚解,只把直观的理解说明一下。要保证C1C_1C1只有内容特征,且是完整的内容特征的方法是,控制C1C_1C1的维度。开源代码中,这个维度是32维。
如图3-2所示,如果C1C_1C1的维度太大的话,如(a),会把语者的特征也包括进去,这个时候对自重建能力是没有影响的,但是如果拿C1C_1C1去训练一个speaker classification模型的话,模型的准确率就会比较高;如果C1C_1C1的维度太小的话,如(b),最终自重建出来的误差会比较大;如果C1C_1C1的维度刚刚好的话,如©,是的自重建误差也比较小,用C1C_1C1去训练一个speaker classification模型的准确率也比较小。
作者就是按这种方式来确定,下表就是不同C1C_1C1维度下,得到的自重建误差和语者分类器准确率的表。
参考资料
[1] AUTOVC: Zero-Shot Voice Style Transfer with Only Autoencoder Loss
[2] https://github.com/auspicious3000/autovc
[3] https://github.com/babysor/MockingBird
[4] https://github.com/jik876/hifi-gan