填充
填充(padding):在输入图像的边界填充元素(通常填充元素是 0)
填充 ph 行和 pw 列,输出形状为:
(nh−kh+ph+1)×(nw−kw+pw+1)
通常取 ph=kh−1,pw=kw−1
- 当 kh 为奇数时在上下两侧填充 ph/2
- 当 kh 为偶数时,在上上侧填充 ⌈ph/2⌉,在下侧填充 ⌊ph/2⌋
卷积神经网络中卷积核的高度和宽度通常为奇数,选择奇数的好处是,保持空间维度的同时,可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列。
步幅
步幅(stride):每次滑动的步长(滑动元素的数量)
垂直步幅为 3,水平步幅为 2 的二维互相关运算:
当垂直步幅为 sh、水平步幅为 sw 时,输出形状为:
⌊(nh−kh+ph+sh)/sh⌋×⌊(nw−kw+pw+sw)/sw⌋
如果 ph=kh−1,pw=kw−1,则输出形状简化为:
⌊(nh+sh−1)/sh⌋×⌊(nw+sw−1)/sw⌋
如果输入的高度和宽度可以被垂直和水平步幅整除,则输出形状将为:
(nh/sh)×(nw/sw)
总结
- 填充和步幅是卷积层的超参数
- 填充在输入周围添加行/列,来控制输出的减少量
- 步幅是每次滑动核窗口时行/列的步长,可以成倍减少输出形状
代码实现
在所有侧边填充 1 个像素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import torch from torch import nn
def comp_conv2d(conv2d, X): X = X.reshape((1, 1) + X.shape) Y = conv2d(X) return Y.reshape(Y.shape[2:])
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1) X = torch.rand(size=(8, 8)) comp_conv2d(conv2d, X).shape
|
填充不同的高度和宽度
1 2
| conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1)) comp_conv2d(conv2d, X).shape
|
将高度和宽度的步幅设置为2
1 2
| conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2) comp_conv2d(conv2d, X).shape
|
一个稍微复杂的例子
1 2
| conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4)) comp_conv2d(conv2d, X).shape
|