下面这支影片我们可以看到那时候的声码器是一台大型机器,在影片 39 秒的地方你可以听听那段惨不忍赌的合成人声,但在那个时候却是奇蹟。
如果你很有兴趣想知道那台老古董是怎麽发出声音的话,你可以看一下这篇文章的介绍
然而我们不会用 WaveNet_Vocoder 来做,因为它实在是太慢了。
想像一下不管是图片或是声音,下一个元素的产生或多或少都与前一个元素有关,在图片上的话最直观的理解就是渐层。
WaveNet 中使用了和 PixelCNN 相同的 Gated Activation Unit,这个东西就类似激励函数,只是它是非线性的,在这里使用会比单纯做 ReLU 好 (因为 ReLU 会把小於 0 的都丢掉)。
# 把输入分别丢进 sigmoid 跟 tanh, 然後把结果乘起来
def gate(x):
res_sigmoid = sigmoid(x)
res_tanh = tanh(x)
res = Multiply()([res_sigmoid, res_tanh])
return res
如上图所示, 输入经过因果卷积之後分别进入由膨胀卷积跟 Gated Activation Unit 所组成的 Residual Block, 以及 skip-connections,最後把所有结果相加起来再过 softmax 就是输出结果。
def residual_block(x,filters,kernel_size,rate):
x = dilated_conv(filters,kernel_size,rate)(x)
x = gate(x)
x = conv_1D(32,1)(x) # 最後那个 [1*1]
return x
稍微了解 WaveNet 的架构之後,我们现在来谈谈怎麽用 WaveNet 做 vocoder
输入的条件还可以有两种形式分别是:
全局条件:
整个 model 都照条件去做, 加入之後 Gated Activation Unit 变成
局部条件:
限定 model 在什麽时候才照条件去做,加入之後 Gated Activation Unit 变成
在 WaveNet 局部条件的输入原本是一个 Transpose Conv 它在文字转语音 (TTS)的做法是先训练一个 CNN 的语音转文字模型 (h = F(y)) 然後再把它 Transpose 回来 (y = f(h)), 通过这个将文字转换成语音,但这样生出来的语音品质非常糟糕,所以不会直接使用,而是拿来当作局部条件的输入,而输入的 ground truth 就是真正的语音。
而这边的 Vf,k*y 就是 1X1 Conv 它是拿来取代 Transpose 的,经过实验证明效果比较好。
同 TTS 的原理,你只要把局部条件换成语音特徵 (mel) 它就变成 Vocoder 了。
如果有兴趣想做看看的话,你可以在这里找到我完整的 DEMO (没有加条件的部分),这个 repo 适用在 tf2.0+ 。
Deep Mind 并没有释出他们官方的 Code,不过坊间有不少 implement (目前我看到的大多只做到全局条件),你可以在这里找到
今天我们谈了 Vocoder 它是进行声音分析与合成的系统,也对 WaveNet 做了简略的介绍,其实 WaveNet 後来进化出许多快速的版本,像是 Parallel Wavenet 跟 WaveRNN,但我没研究这些版本有没有拿来训练 Vocoder; 而 Vocoder 除了 WaveNet 的作法之外也有很多其他的做法,之後会在做介绍,感谢您的收看 ~ 我们明天再见。
结果 meeting 延期, 多了一个礼拜,赚烂了 XD
>>: [Angular] Day7. Content projection
Reduce-Side Joins and Grouping 当 MapReuce Job 执行时,...
如果讲了自动编码器(AE), 却不介绍变分自动编码器(VAE), 感觉有点太可惜了。 听到生成演算法...
讲了两天的赣话,今天终於要来实作啦! The BotFather The Botfather 这个...
T0838 Modify Alarm Settings 攻击者修改设备的警告功能设定(如直接停止警告...
什麽是 App Shortcuts App Shortcuts 提供程序快速启动选单,透过这个捷径用...