conv1d卷积维度变化
conv1d中的网络层的卷积维度变化一直是一个非常让人头疼的地方,尤其是本身理解了kernel_size加入之后的维度变化后,又加入了dilation的参数,这下直接让像我一样的大多数小白直接懵比了。这里通过dilation以及kernel_size的变化,来探求卷积维度的变化
dilation = 1时的情形
当dilation = 1的时候,输出的最后一个维度为原始维度减去kernel_size+1
这里输出的最后一维为8-3+1 = 6,画图理解这一维度的变化
dilation=2的时候对应维度
首先kernel=3的时候整体总共为6个,这里我们先画出6个分割出来的矩阵
当dilation=1的时候,输出的维度没有任何的放大,正是上面的6个矩阵的内容
当dilation=2的时候,输出的维度两两合并,形成了新的矩阵
注意:dilation=2的时候左右结合,相当于dilation=1的情况下再加上1,中心左右各偏移一位,所以是上图的结果
dilation=3时的对应维度
推导公式部分
原始总的矩阵为8个,经历了kernel_size之后变为6个,这段代码较为容易推导,输出维度为
8 − k e r n e l _ s i z e + 1 = 6 8-kernel\_size+1 = 6 8−kernel_size+1=6个,
接下来dilation=1的时候维度保持不变,每增加一次dilation的时候,左右两边同时延伸一个维度,所以每增加一次dilation的时候,输出维度减少2,推导出对应的公式
6 − ( d i l a t i o n − 1 ) ∗ 2 6-(dilation-1)*2 6−(dilation−1)∗2,最终的维度为 8 − k e r n e l _ s i z e + 1 − ( d i l a t i o n − 1 ) ∗ 2 = 8 − k e r n e l _ s i z e − d i l a t i o n ∗ 2 + 3 8-kernel\_size+1-(dilation-1)*2 = 8-kernel\_size-dilation*2+3 8−kernel_size+1−(dilation−1)∗2=8−kernel_size−dilation∗2+3
列一个对应的公式
原 始 维 度 − k e r n e l _ s i z e − d i l a t i o n ∗ 2 + 3 + p a d d i n g ∗ 2 = 现 有 维 度 ( 1 ) 原始维度-kernel\_size-dilation*2+3+padding*2 = 现有维度 (1) 原始维度−kernel_size−dilation∗2+3+padding∗2=现有维度(1)
此时如果想要原始维度跟现有维度保持一致的情况下
原 始 维 度 = 现 有 维 度 ( 2 ) 原始维度 = 现有维度(2) 原始维度=现有维度(2)
得到padding的相应公式
p a d d i n g = k e r n e l _ s i z e + d i l a t i o n ∗ 2 − 3 2 padding = \frac{kernel\_size+dilation*2-3}{2} padding=2kernel_size+dilation∗2−3
这里计算padding的时候需要特别注意的一点是,padding是左右两边都填补空白,所以只要有padding两侧的空白都会被填充上
如果前面的 k e r n e l s i z e + d i l a t i o n ∗ 2 − 3 kernel_size+dilation*2-3 kernelsize+dilation∗2−3不能整除2的话,则无论如何填补,最终都不能跟原始的维度保持一致
膨胀卷积神经网络的结构
注意这里膨胀卷积神经网络的结构
def build(self,input_shape):
super(ResidualGatedConv1D,self).build(input_shape)
self.conv1d = Conv1D(
filters=self.filters*2,
kernel_size=self.kernel_size,
dilation_rate=self.dilation_rate,
padding='same',
)
self.layernorm = LayerNormalization()
if self.filters != input_shape[-1]:
self.dense = Dense(self.filters, use_bias=False)
self.alpha = self.add_weight(
name='alpha', shape=[1], initializer='zeros'
)
注意这一块之中的self.alpha是带有梯度的,初始化的参数为0
def call(self, inputs, mask=None):
if mask is not None:
mask = K.cast(mask, K.floatx())
inputs = inputs * mask[:, :, None]
outputs = self.conv1d(inputs)
gate = K.sigmoid(outputs[..., self.filters:])
outputs = outputs[..., :self.filters] * gate
outputs = self.layernorm(outputs)
if hasattr(self, 'dense'):
inputs = self.dense(inputs)
return inputs + self.alpha * outputs
这里的输入会引起最终结果的变化,原因是self.alpha与outputs相乘得到结果,而outputs是由inputs向量得来的内容
总结
通俗地讲,每一个dilation之后,矩阵会向两边扩展,即每次dilation+1的时候,中间的间距会增加2,进而能够推导出需要padding的层数