conv1d膨胀卷积网络输出解析


conv1d中的网络层的卷积维度变化一直是一个非常让人头疼的地方,尤其是本身理解了kernel_size加入之后的维度变化后,又加入了dilation的参数,这下直接让像我一样的大多数小白直接懵比了。这里通过dilation以及kernel_size的变化,来探求卷积维度的变化

dilation = 1时的情形

当dilation = 1的时候,输出的最后一个维度为原始维度减去kernel_size+1
输出图片1这里输出的最后一维为8-3+1 = 6,画图理解这一维度的变化
输出维度1的时候切分过程

dilation=2的时候对应维度

首先kernel=3的时候整体总共为6个,这里我们先画出6个分割出来的矩阵
六个分割出来的对应的矩阵内容当dilation=1的时候,输出的维度没有任何的放大,正是上面的6个矩阵的内容
dilation=1矩阵未被放大当dilation=2的时候,输出的维度两两合并,形成了新的矩阵
dilation=2的时候矩阵结合情况注意:dilation=2的时候左右结合,相当于dilation=1的情况下再加上1,中心左右各偏移一位,所以是上图的结果
dilation=2运行结果

dilation=3时的对应维度

dilation=3时对应的维度dilation=3的运行结果

推导公式部分

原始总的矩阵为8个,经历了kernel_size之后变为6个,这段代码较为容易推导,输出维度为
8 − k e r n e l _ s i z e + 1 = 6 8-kernel\_size+1 = 6 8kernel_size+1=6个,
接下来dilation=1的时候维度保持不变,每增加一次dilation的时候,左右两边同时延伸一个维度,所以每增加一次dilation的时候,输出维度减少2,推导出对应的公式
6 − ( d i l a t i o n − 1 ) ∗ 2 6-(dilation-1)*2 6(dilation1)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 8kernel_size+1(dilation1)2=8kernel_sizedilation2+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_sizedilation2+3+padding2=(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+dilation23
这里计算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+dilation23不能整除2的话,则无论如何填补,最终都不能跟原始的维度保持一致
输出维度1
输出维度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的层数

Guess you like

Origin blog.csdn.net/znevegiveup1/article/details/121067573