(四)卷积神经网络 -- 2 填充和步幅

2. 填充和步幅

在1.1小节的示例中,使用高和宽为3的输入与高和宽为2的卷积核得到高和宽为2的输出。

一般来说,假设输入形状是 n h × n w n_h\times n_w nh×nw,卷积核窗口形状是 k h × k w k_h\times k_w kh×kw,那么有输出形状为:

( n h − k h + 1 ) × ( n w − k w + 1 ) (n_h-k_h+1) \times (n_w-k_w+1) (nhkh+1)×(nwkw+1)

由此可见,卷积层的输出形状由输入形状和卷积核窗口形状决定。

本节将介绍卷积层的两个超参数:填充(padding)和步幅(stride),可以对给定形状的输入和卷积核改变输出形状。


2.1 padding

2.1.1 概念

填充(padding)是指在输入高和宽的两侧填充元素(通常是0元素)。

如下图所示,在原输入高和宽的两侧分别添加了值为0的元素,使得输入高和宽从3变成了5,从而使得输出高和宽由2增加到4。

图中的阴影部分,为第一个输出元素及其计算所使用的输入和核数组元素:
0 × 0 + 0 × 1 + 0 × 2 + 0 × 3 = 0 0\times0+0\times1+0\times2+0\times3=0 0×0+0×1+0×2+0×3=0


一般来说,若在高的两侧一共填充 p h p_h ph行,在宽的两侧一共填充 p w p_w pw列,那么有输出形状为:

( n h − k h + p h + 1 ) × ( n w − k w + p w + 1 ) , (n_h-k_h+p_h+1)\times(n_w-k_w+p_w+1), (nhkh+ph+1)×(nwkw+pw+1),

即,输出的高和宽会分别增加 p h p_h ph p w p_w pw


在很多情况下,会设置 p h = k h − 1 p_h=k_h-1 ph=kh1 p w = k w − 1 p_w=k_w-1 pw=kw1来使输入和输出具有相同的高和宽,从而方便在构造网络时推测每个层的输出形状。

k h k_h kh为奇数,会在高的两侧分别填充 p h / 2 p_h/2 ph/2行;
k h k_h kh为偶数,一种可能是在输入的顶端一侧填充 ⌈ p h / 2 ⌉ \lceil p_h/2\rceil ph/2行(上入整数),而在底端一侧填充 ⌊ p h / 2 ⌋ \lfloor p_h/2\rfloor ph/2行(下舍整数)。
在宽的两侧填充同理。

卷积神经网络经常使用奇数高宽的卷积核,如1、3、5和7,因此两端上的填充个数相等。


2.1.2 代码示例

import tensorflow as tf
print(tf.__version__)
2.0.0

对任意的二维数组X,设它的第i行第j列的元素为X[i,j]
当两端上的填充个数相等,并使输入和输出具有相同的高和宽时,可知输出Y[i,j]是由输入以X[i,j]为中心的窗口同卷积核进行互相关计算得到的。

示例:创建一个高和宽为3的二维卷积层,设输入高和宽两侧的填充数分别为1,给定一个高和宽为8的输入,发现输出的高和宽也是8。

def comp_conv2d(conv2d, X):
    
    # shape: (8,8) to (1,8,8,8,1)
    X = tf.reshape(X, shape=(1,)+X.shape+(1,))
    Y = conv2d(X)
    
    # shape: (1,8,8,8,1) to (8,8) 
    return tf.reshape(Y, shape=Y.shape[1:3])
X = tf.random.uniform(shape=(8,8))
conv2d = tf.keras.layers.Conv2D(filters=1, kernel_size=3, padding='same')

comp_conv2d(conv2d,X).shape

输出:

TensorShape([8, 8])


2.2 stride

2.2.1 概念

在1.1小节介绍的二维互相关运算中,卷积窗口从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动。这里将每次滑动的行数和列数称为步幅(stride)。

在已有示例中,涉及的高和宽两个方向上的步幅均为1,也可以使用更大步幅。
在高上步幅为3、在宽上步幅为2的二维互相关运算,如下图所示:

由此可见,输出第一列第二个元素时,卷积窗口向下滑动了3行;输出第一行第二个元素时,卷积窗口向右滑动了2列。
当卷积窗口在输入上再向右滑动2列时,由于输入元素无法填满窗口,无结果输出。

图中的阴影部分,为输出元素及其计算所使用的输入和核数组元素: 0 × 0 + 0 × 1 + 1 × 2 + 2 × 3 = 8 0 × 0 + 6 × 1 + 0 × 2 + 0 × 3 = 6 0\times0+0\times1+1\times2+2\times3=8\\ 0\times0+6\times1+0\times2+0\times3=6 0×0+0×1+1×2+2×3=80×0+6×1+0×2+0×3=6


一般来说,当高上步幅为 s h s_h sh,宽上步幅为 s w s_w sw时,输出形状为(均取下舍整数):

⌊ ( n h − k h + p h + s h ) / s h ⌋ × ⌊ ( n w − k w + p w + s w ) / s w ⌋ \lfloor(n_h-k_h+p_h+s_h)/s_h\rfloor \times \lfloor(n_w-k_w+p_w+s_w)/s_w\rfloor (nhkh+ph+sh)/sh×(nwkw+pw+sw)/sw

若设 p h = k h − 1 p_h=k_h-1 ph=kh1 p w = k w − 1 p_w=k_w-1 pw=kw1,那么输出形状将简化为:
⌊ ( n h + s h − 1 ) / s h ⌋ × ⌊ ( n w + s w − 1 ) / s w ⌋ \lfloor(n_h+s_h-1)/s_h\rfloor \times \lfloor(n_w+s_w-1)/s_w\rfloor (nh+sh1)/sh×(nw+sw1)/sw

更进一步,若输入的高和宽能分别被高和宽上的步幅整除,那么输出形状将是:
( n h / s h ) × ( n w / s w ) (n_h/s_h) \times (n_w/s_w) (nh/sh)×(nw/sw)


2.2.2 代码示例

示例1

令高和宽上的步幅均为2,从而使输入的高和宽减半。

conv2d = tf.keras.layers.Conv2D(filters=1, kernel_size=3, padding='same', strides=2)
comp_conv2d(conv2d, X).shape

输出:

TensorShape([4, 4])

示例2

令padding=‘valid’,高上的步幅为3,宽上的步幅为4。

conv2d = tf.keras.layers.Conv2D(filters=1, kernel_size=(3,5), padding='valid', strides=(3,4))
comp_conv2d(conv2d, X).shape

输出:

TensorShape([2, 1])

  • 记:padding=‘same’ vs padding=‘valid’ ?


参考

《动手学深度学习》(TF2.0版)

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值