参与11月更文挑战的第23天,活动详情查看:2021最后一次更文挑战
需要接着动手学深度学习6.1 为什么需要卷积层 | 卷积公式推导看。
经过第一节的推到和演示,我们已经能get到卷积的输出形状取决于输入形状和卷积核的形状。
输入的大小为 ,卷积核的大小为 ,那输出的大小就是 。
其实除此之外,影响卷积核大小的还有填充和步幅。
填充padding
所谓的填充就是给图片加边。
现在我给图片外边加上一像素的边。
那计算结果就从 变为 了。
每条边加上1像素也就是多出两行,多出两列。那结果矩阵也是多出两行两列。
一般的情况下,我们需要设置 和 ,这样就可以使输入和输出具有相同的高度和宽度。
- p输入矩阵
- k卷积核
假设 是奇数,我们将在高度的两侧填充 行。
如果 是偶数,则一种可能性是在输入顶部填充 行,在底部填充 行。
填充宽度的两侧同理。
选择奇数的好处是,保持空间维度的同时,我们可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列。
对于任何二维张量 X
,当满足:
- 内核的大小是奇数;
- 所有边的填充行数和列数相同;
- 输出与输入具有相同高度和宽度
则可以得出:输出 Y[i, j]
是通过以输入 X[i, j]
为中心,与卷积核进行互相关计算得到的。
import torch
from torch import nn
复制代码
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
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列
X = torch.rand(size=(5, 8))
print(comp_conv2d(conv2d, X).shape)
复制代码
>>
torch.Size([5, 8])
复制代码
- 经过卷积操作之后大小不变,还是5*8的张量。
- 注意这里
X.reshape((1, 1) + X.shape)
,两个元组相加是拼接,不是数字相加嗷。
步幅strides
步幅呢就是每次挪动的大小,之前我们都是默认挪动一个,那现在默认挪动两个呢?
那计算结果就从 变为 了。
通常,当垂直步幅为 、水平步幅为 时,输出形状为
如果我们设置了 和 ,则输出形状将简化为 。 更进一步,如果输入的高度和宽度可以被垂直和水平步幅整除,则输出形状将为 。
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
复制代码
>>py
torch.Size([3, 4])
复制代码
接上边的代码中的X用,把二维交叉运算的步幅设置为横向纵向都是2,由此可以得到结果也是缩小的,并且符合上边推出来的公式。
-
《动手学深度学习》系列更多可以看这里:《动手学深度学习》专栏(juejin.cn)
-
笔记Github地址:DeepLearningNotes/d2l(github.com)
还在更新中…………