WaveNet是2016年Google DeepMind 提出的一种Neural Vocoder 架构,模型主体为一个基于空洞因果卷积(Dilated Causal Convolution)的概率模型。即基于Condition(Mel Spectrogram),以及之前时间节点的语音生成一个概率分布,再采样得到下一采样点。反复执行该步骤,最后得到完整语音。
本文的目标是以可复现为目标的讲述WaveNet的模型结构,以及推断(Inference)过程。并且着重叙述空洞卷积(Dilated Conv)残差块,因为之后很大一部分Neural Vocoder都会使用这个组件。讲述当中会有部分个人看法,见谅(仅仅是个人对模型结构设计的猜测)。
一、WaveNet 初衷
WaveNet的出发点十分简单,即当前采样点的概率分布依赖于之间时间点,换言之,我们可以用之前采样点作为条件的概率分布来描述当前时间点。从宏观角度(也就整段语音)来说,语音的概率分布实际就是每个时间点的条件概率分布的联合分布。可以引用论文中的公式:
其中x_t表示,时间点t对应的语音采样点。需要注意下文中使用的都是采样率固定的语音的离散表达形式。
基于这个想法出发,WaveNet的核心思路就转换成了对于每个采样点的条件概率分布建模,这里的条件(Condition)既包括了之前时间点,也包括对应时间的语音学特征(这里使用Mel Spectrogram)。
所以现在问题有二,1 这个模型的结构是什么样的。 2 推断(inference)过程是如何对对应采样点从概率分布中采样的。
二、 模型结构
1 模型框架
WaveNet的模型结构部分参照PixelCNN,训练通过 对数似然估计 (log-likelihoods) 学习参数。模型结构十分简单:
可以看到模型主体是 k层网络块,通过Skip-connections 以及两个激活函数和1x1卷积层,最后加上Softmax层。
先需要确保除去Causal Conv, Dilated Conv, Skip-connections,是能够理解这个模型的。
当然 残差(Residual)这种模型方法是极为常见的,可以抽象概括为 在模型块的输出中额外加上模型块的输入,即 f(x) = x + g(x) 其中 g(.) 就是模型块。残差(Residual) 其实就是那个加号,就这么简单。好处是避免层数过深,参数无法训练。
然后剩下的就是ReLU激活函数和Softmax层了,这两个函数是不带可训练参数的,是两个结构数值都固定的函数。就是两个固定函数。
那么下文开始介绍比较有特色的Causal Conv, Dilated Conv, Skip-connections 结构,实际从数学角度来说,这三个东西比Residual,ReLU激活函数和Softmax层 好理解得多的多。
2 空洞因果卷积(Dilated Causal Convolution)
这种卷积层有两个前缀,一个Dilated, 一个Causal,先考虑因果(Causal)这个前缀。从语义理解得角度来说,因果卷积实际就是考虑到时序得因果关系得卷积。需要注意这里要考虑的是一维卷积,毕竟时间轴只有一条。
我们可以从图中看出这卷积的输出只依赖之前时间点的输入。举个例子,第一层隐藏层在时间下标为 t 的输出只依赖 时间 t-1 和时间 t 的输入,转成数学语言就是 hidden out = f(x_{t-1}, x_t) 。
那么我们能不能跳着使用之前的时间节点呢,毕竟只使用t-1 时间点感觉"看"得很窄,感受野很小。如果使用 t-2 时间点 或 t-4时间点呢? 这其实就是空洞卷积(Dilated Conv)的想法了。
其中的 t-d 中的 d就是Dilation,也就是需要跳跃的时间间隔。 计算过程中我们可以每层都使用不同的Dilation(一般是逐步加大),这样感受野就大幅扩大,尤其对于语音这种前后时间依赖极强的实例非常有效。
3 跳步连接(Skip-connections)
Skip-connections 其实和残差方法极为类似,将各隐藏层的隐藏特征累加起来作为最后输出,实际表达为 : output = hidden_out1 + hidden_out2 + … + hidden_outn。
这样的好处是加速网络训练,同时防止网络过深导致的部分层的梯度消失。个人理解其实除了这些Skip-connections单独优势,还有个和空洞卷积Dilated conv 联合的作用。
模型中的每个卷积块使用的空洞卷积的Dilation实际是不同的,对于语音来说不同的Dilation可以等效于聚焦不同的频率,也就是说每个卷积块的关注的频率被人为的逐层过滤了,然后再通过 Skip-connections 进行整合。预测下一时间点的概率分布。 Skip-connections这里也起到了整合分频带的作用。
4 激活函数
这里说激活函数是说残差块内的激活函数,这里使用的是 tanh 和sigmoid的乘积。 不使用ReLU是可以理解的,因为ReLU的输出只有正数,而语音波形有正有负,所以不能使用ReLU。
WaveNet使用了两个激活函数作为代替的目的是想要进行分工,sigmoid负责学习振幅,tanh负责学习相位和频率。这一步倒是十分贴合一些传统的Vocoder方法。理想情况下对于不同频率下的相位和振幅建模,该点也是证明上述中 Skip-connections这里也起到了整合分频带的作用 的佐证之一。
5 条件(Condition)添加
上述过程中只讲述了输入是之前语音序列的情况,模型的输入为序列x, x为时间点t之前的语音序列。实际上我们不能单单通过之前的语音预测下一个点,就比方说如果单独输入一个 “我”字,是无法预测到底是“我吃饭”还是“我睡觉”的,所以还需要添加一个条件(Condition)来限制预测方向。
对于Vocoder来说这个条件就是频谱特征,比较常用的是Mel Spectorgram。这个特征以帧为单位变化。这样就可以正确的指定预测方向了。
现在问题就变成了如何添加Conditon。WaveNet的方法是在激活函数 tanh和sigmoid之前添加condition,在直接加上condition之前还可以稍稍变换下condition。因而让condition通过一个1x1卷积层,然后加入激活函数。可写为:
其中 x 为之前时间的语音,h为condition输入, V就是1x1卷积层参数,W是空洞因果卷积,z是输出。
三、 推断(Inference)
也许看到这里大部分人认为Inference的部分没必要讲了,这一部分主要是针对对于概率模型inference不太熟悉的读者。
关键点是千万不要认为Softmax后的输出就是当前时间采样点的数值!
千万不要认为Softmax后的输出就是当前时间采样点的数值!
千万不要认为Softmax后的输出就是当前时间采样点的数值!
还记得在开头说的,WaveNet的输出是个概率模型吗。这里提供两种inference方法,一种是论文里的softmax后的概率模型,一种是高斯混合模型。
1 Softmax概率模型
这里涉及一个语音的知识先说明下:
语音的采样点存储方式一般是 16-bit Signed Integer PCM,也就是一个16比特的整数,但这样概率模型就相当于有65536种可能性,这样概率模型的就需要输出65536维概率。这非常不现实。所以需要采样点的量化,这里使用的是mu-law 量化方式,量化后可以将采样点表示为8比特的整数,也就是下降到了256种可能性,这样就比较好计算了。
每个数值的可能性可以通过Softmax计算,也就是我们每次得到256维的概率向量,代表的是量化后的数值的可能性,然后通过这个离散分布采样一个概率数值。
概率数值通过下式还原得到采样点数值。
2 高斯混合模型
这个模型也很好理解,假设我们建立的是三个高斯的高斯混合模型,那么如何表达这个模型呢?
简单,均值和方差能够确定一个高斯概率分布,那么三个均值和方差就能确定三个高斯的高斯混合模型。也就是六个参数就能够表达这个高斯混合模型了。
那么我们的输出预测就应该是6个靠近0的数(因为采样点取值范围在0附近),这六个数是表示高斯混合模型的参数。然后建立对应的高斯混合分布,再采样,就得到了当前时间的采样点。
实际操作中,WaveNet的模型输出也就是一个2N维的向量,对应的是N个高斯的高斯混合模型。
Reference
WaveNet: A Generative Model for Raw Audio
Conditional image generation with PixelCNN decoders
作者:一力徐羊
文章来源:知乎
推荐阅读
更多芯擎AI开发板干货请关注芯擎AI开发板专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。