# 5.2 填充和步幅
在上一节的例子里,我们使用高和宽为3的输入与高和宽为2的卷积核得到高和宽为2的输出。一般来说,假设输入形状是`$ n_h\times n_w $`,卷积核窗口形状是`$ k_h\times k_w $`,那么输出形状将会是
```[tex]
(n_h-k_h+1) \times (n_w-k_w+1).
```
所以卷积层的输出形状由输入形状和卷积核窗口形状决定。本节我们将介绍卷积层的两个超参数,即填充和步幅。它们可以对给定形状的输入和卷积核改变输出形状。
## 5.2.1 填充
填充(padding)是指在输入高和宽的两侧填充元素(通常是0元素)。图5.2里我们在原输入高和宽的两侧分别添加了值为0的元素,使得输入高和宽从3变成了5,并导致输出高和宽由2增加到4。图5.2中的阴影部分为第一个输出元素及其计算所使用的输入和核数组元素:`$ 0\times0+0\times1+0\times2+0\times3=0 $`。
:-: ![](https://img.kancloud.cn/95/a7/95a706af2505e02f347028265e12bd1d.svg)
<div align=center>图5.2 在输入的高和宽两侧分别填充了0元素的二维互相关计算</div>
一般来说,如果在高的两侧一共填充`$ p_h $`行,在宽的两侧一共填充`$ p_w $`列,那么输出形状将会是
```[tex]
(n_h-k_h+p_h+1)\times(n_w-k_w+p_w+1),
```
也就是说,输出的高和宽会分别增加`$ p_h $`和`$ p_w $`。
在很多情况下,我们会设置`$ p_h=k_h-1 $`和`$ p_w=k_w-1 $`来使输入和输出具有相同的高和宽。这样会方便在构造网络时推测每个层的输出形状。假设这里`$ k_h $`是奇数,我们会在高的两侧分别填充`$ p_h /2 $`行。如果`$ k_h $`是偶数,一种可能是在输入的顶端一侧填充`$ \lceil p_h/2\rceil $`行,而在底端一侧填充`$ \lfloor p_h/2\rfloor $`行。在宽的两侧填充同理。
卷积神经网络经常使用奇数高宽的卷积核,如1、3、5和7,所以两端上的填充个数相等。对任意的二维数组`X`,设它的第`i`行第`j`列的元素为`X[i,j]`。当两端上的填充个数相等,并使输入和输出具有相同的高和宽时,我们就知道输出`Y[i,j]`是由输入以`X[i,j]`为中心的窗口同卷积核进行互相关计算得到的。
下面的例子里我们创建一个高和宽为3的二维卷积层,然后设输入高和宽两侧的填充数分别为1。给定一个高和宽为8的输入,我们发现输出的高和宽也是8。
``` python
import torch
from torch import nn
# 定义一个函数来计算卷积层。它对输入和输出做相应的升维和降维
def comp_conv2d(conv2d, X):
# (1, 1)代表批量大小和通道数(“多输入通道和多输出通道”一节将介绍)均为1
X = X.view((1, 1) + X.shape)
Y = conv2d(X)
return Y.view(Y.shape[2:]) # 排除不关心的前两维:批量和通道
# 注意这里是两侧分别填充1行或列,所以在两侧一共填充2行或列
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=3, padding=1)
X = torch.rand(8, 8)
comp_conv2d(conv2d, X).shape
```
输出:
```
torch.Size([8, 8])
```
当卷积核的高和宽不同时,我们也可以通过设置高和宽上不同的填充数使输出和输入具有相同的高和宽。
``` python
# 使用高为5、宽为3的卷积核。在高和宽两侧的填充数分别为2和1
conv2d = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
```
输出:
```
torch.Size([8, 8])
```
## 5.2.2 步幅
在上一节里我们介绍了二维互相关运算。卷积窗口从输入数组的最左上方开始,按从左往右、从上往下的顺序,依次在输入数组上滑动。我们将每次滑动的行数和列数称为步幅(stride)。
目前我们看到的例子里,在高和宽两个方向上步幅均为1。我们也可以使用更大步幅。图5.3展示了在高上步幅为3、在宽上步幅为2的二维互相关运算。可以看到,输出第一列第二个元素时,卷积窗口向下滑动了3行,而在输出第一行第二个元素时卷积窗口向右滑动了2列。当卷积窗口在输入上再向右滑动2列时,由于输入元素无法填满窗口,无结果输出。图5.3中的阴影部分为输出元素及其计算所使用的输入和核数组元素:
`$ 0\times0+0\times1+1\times2+2\times3=8 $`、
`$ 0\times0+6\times1+0\times2+0\times3=6 $`。
:-: ![](https://img.kancloud.cn/da/04/da041d711e41d2fe6bbc0ada2c492bba.svg)
<div align=center>图5.3 高和宽上步幅分别为3和2的二维互相关运算</div>
一般来说,当高上步幅为`$ s_h $`,宽上步幅为`$ s_w $`时,输出形状为
```[tex]
\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.
```
如果设置`$ p_h=k_h-1 $`和`$ p_w=k_w-1 $`,那么输出形状将简化为`$ \lfloor(n_h+s_h-1)/s_h\rfloor \times \lfloor(n_w+s_w-1)/s_w\rfloor $`。更进一步,如果输入的高和宽能分别被高和宽上的步幅整除,那么输出形状将是`$ (n_h/s_h) \times (n_w/s_w) $`。
下面我们令高和宽上的步幅均为2,从而使输入的高和宽减半。
``` python
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
```
输出:
```
torch.Size([4, 4])
```
接下来是一个稍微复杂点儿的例子。
``` python
conv2d = nn.Conv2d(1, 1, kernel_size=(3, 5), padding=(0, 1), stride=(3, 4))
comp_conv2d(conv2d, X).shape
```
输出:
```
torch.Size([2, 2])
```
为了表述简洁,当输入的高和宽两侧的填充数分别为`$ p_h $`和`$ p_w $`时,我们称填充为`$ (p_h, p_w) $`。特别地,当`$ p_h = p_w = p $`时,填充为`$ p $`。当在高和宽上的步幅分别为`$ s_h $`和`$ s_w $`时,我们称步幅为`$ (s_h, s_w) $`。特别地,当`$ s_h = s_w = s $`时,步幅为`$ s $`。在默认情况下,填充为0,步幅为1。
## 小结
* 填充可以增加输出的高和宽。这常用来使输出与输入具有相同的高和宽。
* 步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的`$ 1/n $`(`$ n $`为大于1的整数)。
-----------
> 注:除代码外本节与原书此节基本相同,[原书传送门](https://zh.d2l.ai/chapter_convolutional-neural-networks/padding-and-strides.html)
- Home
- Introduce
- 1.深度学习简介
- 深度学习简介
- 2.预备知识
- 2.1环境配置
- 2.2数据操作
- 2.3自动求梯度
- 3.深度学习基础
- 3.1 线性回归
- 3.2 线性回归的从零开始实现
- 3.3 线性回归的简洁实现
- 3.4 softmax回归
- 3.5 图像分类数据集(Fashion-MINST)
- 3.6 softmax回归的从零开始实现
- 3.7 softmax回归的简洁实现
- 3.8 多层感知机
- 3.9 多层感知机的从零开始实现
- 3.10 多层感知机的简洁实现
- 3.11 模型选择、反向传播和计算图
- 3.12 权重衰减
- 3.13 丢弃法
- 3.14 正向传播、反向传播和计算图
- 3.15 数值稳定性和模型初始化
- 3.16 实战kaggle比赛:房价预测
- 4 深度学习计算
- 4.1 模型构造
- 4.2 模型参数的访问、初始化和共享
- 4.3 模型参数的延后初始化
- 4.4 自定义层
- 4.5 读取和存储
- 4.6 GPU计算
- 5 卷积神经网络
- 5.1 二维卷积层
- 5.2 填充和步幅
- 5.3 多输入通道和多输出通道
- 5.4 池化层
- 5.5 卷积神经网络(LeNet)
- 5.6 深度卷积神经网络(AlexNet)
- 5.7 使用重复元素的网络(VGG)
- 5.8 网络中的网络(NiN)
- 5.9 含并行连结的网络(GoogLeNet)
- 5.10 批量归一化
- 5.11 残差网络(ResNet)
- 5.12 稠密连接网络(DenseNet)
- 6 循环神经网络
- 6.1 语言模型
- 6.2 循环神经网络
- 6.3 语言模型数据集(周杰伦专辑歌词)
- 6.4 循环神经网络的从零开始实现
- 6.5 循环神经网络的简单实现
- 6.6 通过时间反向传播
- 6.7 门控循环单元(GRU)
- 6.8 长短期记忆(LSTM)
- 6.9 深度循环神经网络
- 6.10 双向循环神经网络
- 7 优化算法
- 7.1 优化与深度学习
- 7.2 梯度下降和随机梯度下降
- 7.3 小批量随机梯度下降
- 7.4 动量法
- 7.5 AdaGrad算法
- 7.6 RMSProp算法
- 7.7 AdaDelta
- 7.8 Adam算法
- 8 计算性能
- 8.1 命令式和符号式混合编程
- 8.2 异步计算
- 8.3 自动并行计算
- 8.4 多GPU计算
- 9 计算机视觉
- 9.1 图像增广
- 9.2 微调
- 9.3 目标检测和边界框
- 9.4 锚框
- 10 自然语言处理
- 10.1 词嵌入(word2vec)
- 10.2 近似训练
- 10.3 word2vec实现
- 10.4 子词嵌入(fastText)
- 10.5 全局向量的词嵌入(Glove)
- 10.6 求近义词和类比词
- 10.7 文本情感分类:使用循环神经网络
- 10.8 文本情感分类:使用卷积网络
- 10.9 编码器--解码器(seq2seq)
- 10.10 束搜索
- 10.11 注意力机制
- 10.12 机器翻译