文章目录
- 1 什么是Voice Conversion
- 2 实际实现中的细节
- 3 根据数据集分类
- 4 Feature disentangle
- 5 训练技巧
本文为李弘毅老师【Voice Conversion - Feature Disentangle】的课程笔记,课程视频youtube地址,点这里👈(需翻墙)。
下文中用到的图片均来自于李宏毅老师的PPT,若有侵权,必定删除。
文章索引:
上篇 - 1-7 Language Modeling
下篇 - 2-2 CycleGAN and StarGAN
总目录
1 什么是Voice Conversion
Voice Conversion指的就是输入一段声音,输出另一段声音。这两段声音的文字内容是一样的,但其他的某些方面是不一样的。
这个某些方面指的是什么呢?
(1)说话人(Speaker)的转变。就是让这段语音听起来像是另一个人在说一样。
- 不同的人说同样一段话,会有不同的效果;
- 可以用来诈骗(Deep fake);
- 做个性化的语音转换,比如小孩一个人在家,别人敲门时,可以用大人的声音回答;
- 保护个人隐私,从声音中可以获取一个人很多的信息。
(2)说话风格(Speaking Style)的转换。
- 说话情绪的转变,有些人说话很温柔,想要严厉批评别人的时候,可以用这个;
- Normal to Lombard。Normal是指正常环境下说话的声音,Lombard是指在酒吧这种嘈杂环境下说话的声音。做这个的原因是,也许有一天,我们的机器人需要在嘈杂的环境下说话,转成Lombard可以让别人听的更清楚。
- Whisper to Normal。悄悄话转成正常人说话的声音。也许我们在图书馆或者哪里用很轻的声音打电话时,希望电话另一头的人听到的是正常的声音。
- 唱歌技巧转换。比如加弹唇,加颤音。
(3)增强说人话的可理解性(Improving Intelligibility)。
- 说话有障碍的人群说的话,可以被转化成更容易理解的声音。
- 口音转换。比如让中国人说英文时,听不出中国人在说的感觉。
(4)数据增强(Data Augmentation)
- 扩大数据集。
2 实际实现中的细节
在实际的实现中,我们往往会假定输入和输出的长度是一致的,这样会让我们的模型比较简单,一个encoder就够了。同时,输出的声音特征向量不能直接作为语音输出,还差个相位,转化为语音时,还需要一个vocoder。这个vocoder如果做的不好,就会让我们合成的声音听起来比较假,一听就听出来是合成的了。
这次不讲vocoder,只讲voicer conversion的部分。
3 根据数据集分类
用于语音转换的数据集可以是成对的(parallel data),也可以是不成对的(unparallel data)。
成对就是指,同样一段话,让不同的人念一遍。这样的数据往往成本比较高,很难找到很多。如果有这样的数据的话,硬train一发,就可以了。
不成对就是每个说话人说的话,甚至语言都是不一样的。这样的数据往往比较好找。这里就需要借助于图像中风格转换的一些技术。Feature Disentangle,顾名思义,就是说我们的声音信号中包含着各种各样的特征,有关于内容的特征,有关于说话人的特征,有背景噪音的特征等等。我们的目的就是把这些特征给分离开来,然后如果要做speaker的转换的话,就把speaker这部分的特征替换掉就可以了。
4 Feature disentangle
下面在描述时,以speaker的转换为例。同样的方法也可以用来转换其他的特征。
假设我们今天有一个content encoder可以提取出语音中的文字信息;又有一个speaker encoder可以无视文字信息,只提取出说话人的说话特征;还有一个decoder吃content encoder和speaker encoder的输出,然后可以吐出speaker encoder说话人说出content encoder内容的语音了。这就实现了voice conversion。
那么,要怎么训练这两个encoder加上一个decoder呢?训练的总体方法和auto-encoder非常相似,就是经过encoder之后,会有一个特征,然后再把这个特征放进decoder里之后,希望得到输入尽可能一致的声音信号。但是,如果完全按照auto-encoder的方法来训练的话,模型并不知道要把两个encoder分为content和speaker两部分,两个encoder学成一样的也是完全有可能的。如何让模型知道要学一个content的特征,一个speaker的特征就是voice conversion和auto-encoder的区别所在。
目前主要有以下几种方法:
(1)用one-hot向量来代替speaker encoder
一种做法就是,我们干脆不要这个speaker encoder了。我们用一个one-hot encoder的向量来表示是哪个说话人说的。这个做法的前提是,我们知道是哪个说话人说的,且这个说话人属于一个已知的有限集合,如果有一个新的说话人进来,就需要重train这个模型。这个做法的另一个缺点是,没有办法保证content encoder的输出中,不包含说话人相关的特征,不过这个可以通过控制encoder输出的维度来加以限制。此法虽然看似很简单,但却会有还不错的结果。
(2)Pretrained Encoder
另一种做法就是我们先事先train好一个speaker embedding的模型来当作这个speaker encoder,然后再训练的时候,只需要微调一下这个speaker encoder就可以了。至于content encoder的部分,我们也可以用一个事先train好的语音识别的模型来做这个encoder。一般的语音识别的模型都是输出的文字,不太好直接放上去,一个比较好的content encoder就是HMM中用来计算输入的acoustic feature属于哪个state的那个DNN。
这个方案是工业界比较常用的方案。
(3)Adversarial Training
还有一种思路就是在训练content encoder的时候引入对抗学习。我们会添加一个speaker classifier作为discriminator,用来区分这句或是哪个说话人说的,而content encoder就要做到让speaker classifier区别不了这句话是哪个人说的,这样就可以尽可能地保证content encoder中不包含说话人的特征。
(4)设计网络
这里借用了image style transfer中的思想来实现feature dsentangle。首先,会在content encoder这里加上Instance Normalization来去除说人话的相关特征。然后会在decoder上加入一个Adaptive Instance Normalization来加入说话人的特征。
IN(Instance Normalization)就是对输出特征的每一个channel做normalization,因为每一个channel其实代表了模型捕捉到的声音信号中的某一个特征,将这些特征normalize之后,就可以把全局的特征抹去了,也就抹去了说话人的特征。
AdaIN(Adaptive Instance Normalization)是会先对decoder输出的特征加上一个IN,消除说话人的信息,然后再结合speaker encoder的输出,把说话人的信息,也就是全局信息给加上。
5 训练技巧
由于受到训练数据的限制,我们在类似auto-encoder这样traning的时候,从content这一路过来的声音和speaker这一路过来的都是同一个,而我们在testing的时候,却希望content这一路的声音,和speaker这一路过来的不是同一个人。这样我们的模型在testing的时候,表现就会不太好。
事实上,我们在训练的时候没法得到不同speaker从两路过来输出结果的ground truth,所以也只能这样训练。
为了解决这个问题,我们可以做2nd stage的training。这次训练时,两路过来的speaker时不同的,然后我们会把最终的输出放到一个discriminator里去判断这句话是否真实,我们希望输出越真实越好。同时,也会把输出放到一个speaker classifier当中去,来对进行speaker的判断。不过,这样直接train的话,很难train,我们还需要在另外加一个pather作为补偿器,这个patcher和decoder吃一样的输入,然后把输出加到decoder的输出上去。相当于给输出打了一个打补丁。这个补丁在1st stage training的时候是不需要的。
这样的做法可以让模型的效果提升很多。