深度学习-李沐-第六节-填充、步幅、多输入多输出通道

2022 年 8 月 16 日 星期二(已编辑)
这篇文章上次修改于 2024 年 8 月 16 日 星期五,可能部分内容已经不适用,如有疑问可询问作者。

深度学习-李沐-第六节-填充、步幅、多输入多输出通道

填充、步幅、多输入多输出通道

填充

为什么要填充

由于我们通常使用小卷积核,因此对于任何单个卷积,我们可能只会丢失几个像素。 但随着我们应用许多连续卷积层,累积丢失的像素数就多了。 解决这个问题的简单方法即为填充(padding)。

填充定义以及举例

在输入图像的边界填充元素(通常填充元素是0)。

输出大小:(输入-卷积核+步幅+填充)/ 步幅

import torch

from torch import nn


# 重定义一个计算卷积层的函数
# 初始化卷积层权重,对输入输出提高和缩减相应的维数
def comp_conv2d(conv2d, X):

    X = X.reshape((1, 1) + X.shape) # 这里的(1,1)表示批量大小和通道数都是1
    Y = conv2d(X)
    # 省略前两个维度:批量大小和通道
    return Y.reshape(Y.shape[2:])


conv2d = nn.Conv2d(1, 1, kernel_size=5, padding=1)
X = torch.rand(size=(8, 8))
print(comp_conv2d(conv2d, X).shape)

X = torch.rand(size=(8, 8))
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
print(comp_conv2d(conv2d, X).shape)

print("--------------------步幅---------------------")
X = torch.rand(size=(8, 8))
conv2d = nn.Conv2d(1, 1, kernel_size=(3,5),padding=(0,1),stride=(3,4))
print(comp_conv2d(conv2d, X).shape)  # 取整

输出结果:

torch.Size([6, 6])
torch.Size([8, 8])
--------------------步幅---------------------
torch.Size([2, 2])

填充与步幅小结

  • 填充可以增加输出的高度和宽度。这常用来使输出与输入具有相同的高和宽。

  • 步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的(是一个大于的整数)。

  • 填充和步幅可用于有效地调整数据的维度。

多输入多输出通道

多通道输入

当输入包含多个通道时,需要构造一个与输入数据具有相同输入通道数的卷积核,以便与输入数据进行互相关运算。

代码实现

import torch
from d2l import torch as d2l
def corr2d_multi_in(X, K):
    """
    多输入通道计算
    :param X:
    :param K:
    :return:
    """
    # 先遍历“X”和“K”的第0个维度(通道维度),再把它们加在一起
    return sum(d2l.corr2d(x, k) for x, k in zip(X, K))

X = torch.tensor([[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0], [6.0, 7.0, 8.0]],
                  [[1.0, 2.0, 3.0], [4.0, 5.0, 6.0], [7.0, 8.0, 9.0]]])
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])
print(corr2d_multi_in(X, K))
输出:
tensor([[ 56.,  72.],
        [104., 120.]])

多通道输出

在最流行的神经网络架构中,随着神经网络层数的加深,通常会增加输出通道的维数,通过减少空间分辨率以获得更大的通道深度。
每个通道看作是对不同特征的响应。而现实可能更为复杂一些,因为每个通道不是独立学习的,而是为了共同使用而优化的。因此,多输出通道并不仅是学习多个单通道的检测器。
在互相关运算中,每个输出通道先获取所有输入通道再以对应该输出通道的卷积核计算出结果

def corr2d_multi_in_out(X, K):
    """
    计算多通道输出的互相关
    :param X:
    :param K:
    :return:
    """
    return torch.stack([corr2d_multi_in(X, k) for k in K], 0)


K = torch.stack((K, K + 1, K + 2), 0)
print(K.shape)
print(corr2d_multi_in_out(X, K))

输出:
torch.Size([3, 2, 2, 2])
tensor([[[ 56.,  72.],
         [104., 120.]],

        [[ 76., 100.],
         [148., 172.]],

        [[ 96., 128.],
         [192., 224.]]])

1×1卷积

1×1卷积,即Kh = Kw = 1。 1×1卷积的唯一计算发生在通道上。 卷积的本质是有效提取相邻像素间的相关特征

def corr2d_multi_in_out_1x1(X, K):
    c_i, h, w = X.shape
    c_o = K.shape[0]
    X = X.reshape((c_i, h * w))
    K = K.reshape((c_o, c_i))
    # 全连接层中的矩阵乘法
    Y = torch.matmul(K, X)
    return Y.reshape((c_o, h, w))


X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))

Y1 = corr2d_multi_in_out_1x1(X, K)
print(Y1)
Y2 = corr2d_multi_in_out(X, K)
print(Y2)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6

输出:
tensor([[[-1.9456,  0.7056,  0.1425],
         [-0.8588,  0.6740, -0.5521],
         [-0.5984, -1.6677, -1.9896]],

        [[-1.9540,  0.6081,  0.0851],
         [-1.5035,  1.1316,  0.8333],
         [-1.0508, -3.2961, -1.1431]]])
tensor([[[-1.9456,  0.7056,  0.1425],
         [-0.8588,  0.6740, -0.5521],
         [-0.5984, -1.6677, -1.9896]],

        [[-1.9540,  0.6081,  0.0851],
         [-1.5035,  1.1316,  0.8333],
         [-1.0508, -3.2961, -1.1431]]])

多输入多输出通道小结

  • 多输入多输出通道可以用来扩展卷积层的模型。

  • 当以每像素为基础应用时,卷积层相当于全连接层。

  • 1×1卷积层通常用于调整网络层的通道数量和控制模型复杂性。

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...