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的层数