2.2.填充和步幅

我们已经知道,卷积的输出形式取决于输入形式和卷积核的形式。

​ 此外还有其他因素会影响输出的大小。假设以下情景: 有时,在应用了连续的卷积之后,我们最终得到的输出远小于输入大小。这是由于卷积核的宽度和高度通常大于1所导致的。比如,一个240×240像素的图像,经过10层5×5的卷积后,将减少到200×200像素。如此一来,原始图像的边界丢失了许多有用信息。而填充是解决此问题最有效的方法; 有时,我们可能希望大幅降低图像的宽度和高度。例如,如果我们发现原始的输入分辨率十分冗余。步幅则可以在这类情况下提供帮助。

1.填充

​ 容易知道,更大的卷积核可以更快地减小输出大小,但有时我们不想输出变得很小,那么我们可以在输入的周围添加了额外的行/列,这样也可以考虑了角落里数据的特征

在这里插入图片描述

​ 填充后,输出甚至比输入还大了。

​ 填充 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 = k h − 1 , p w = k w − 1 p_h = k_h -1,p_w = k_w -1 ph=kh1,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

2.步幅

​ 填充减小的输出大小与层数线性相关:给定输入大小为224×224,在使用5×5卷积核的情况下,需要44层将输出降低到4×4,需要大量计算才能得到较小输出

​ 步幅是指行/列的滑动步长,有时候为了高效计算或是缩减采样次数,卷积窗口可以跳过中间位置,每次滑动多个元素。

​ 例如一个高度为3,宽度为2的步幅:

在这里插入图片描述

​ 给定高度 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 w = k w − 1 p_h = k_h -1,p_w=k_w-1 ph=kh1,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)

总结

  1. 填充和步幅是卷积层的超参数
  2. 填充在输入周围添加额外的行/列,来控制输出形状的减少量
  3. 步幅是每次滑动核窗口时的行/列的步长,可以成倍的减少输出形状

代码实现

import torch
from torch import nn


# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):
    # 这里的(1,1)表示批量大小和通道数都是1
    X = X.reshape((1, 1) + X.shape)  # +是元组的连接
    Y = conv2d(X)
    # 省略前两个维度:批量大小和通道
    return Y.reshape(Y.shape[2:])


# 请注意,这里每边都填充了1行或1列,因此总共添加了2行或2列
#两个1,1分别为输出通道和输入通道个数
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)  # padding=1是上下左右各添加一行
X = torch.rand(size=(8, 8))
# 输入8,填充2,则为8+2+1-3 =8 ,输出还是8行8列
print(comp_conv2d(conv2d, X).shape)

'''填充不同的高度和宽度'''
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))  # 上下填充2,左右填充1
# 输入8行8列,对于行,填充了4,则为8+4+1-5=8 ,对于列,填充了2,则为8+2+1-3=8,输出还是8行8列
print(comp_conv2d(conv2d, X).shape)

'''步幅'''
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
print(comp_conv2d(conv2d, X).shape)

conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
print(comp_conv2d(conv2d, X).shape)
  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值