多输入多输出通道
我们都知道,彩色图像具有标准的RGB通道来代表红、绿和蓝。
是到目前为止,我们仅展示了单个输入和单个输出通道的简化例子。 这使得我们可以将输入、卷积核和输出看作二维张量。
当我们添加通道时,我们的输入和隐藏的表示都变成了三维张量。例如,每个RGB输入图像具有的 3 × h × w 3 \times h \times w 3×h×w 形状。我们将这个大小 3 3 3 为的轴称为通道(channel)维度。在本节中,我们将更深入地研究具有多输入和多输出通道的卷积核。
多输入通道
当输入包含多个通道时,需要构造一个与输入数据具有相同输入通道数的卷积核,以便与输入数据进行互相关运算。假设输入的通道数为 c i c_i ci ,那么卷积核的输入通道数也需要为 c i c_i ci 。如果卷积核的窗口形状是 k h × k w k_h \times k_w kh×kw ,那么当 c i = 1 c_i = 1 ci=1 时,我们可以把卷积核看作形状为 k h × k w k_h \times k_w kh×kw 的二维张量。
然而,当 c i > 1 c_i > 1 ci>1 时,我们卷积核的每个输入通道将包含形状为 k h × k w k_h \times k_w kh×kw 的张量。将这些张量 c i c_i ci 连结在一起可以得到形状为 c i × k h × k w c_i \times k_h \times k_w ci×kh×kw 的卷积核。由于输入和卷积核都有个 c i c_i ci 通道,我们可以对每个通道输入的二维张量和卷积核的二维张量进行互相关运算,再对通道求和(将 c i c_i ci 的结果相加)得到二维张量。这是多通道输入和多输入通道卷积核之间进行二维互相关运算的结果。
在下图中, 我们演示了一个具有两个输入通道的二维互相关运算的示例。阴影部分是第一个输出元素以及用于计算这个输出的输入和核张量元素:
( 1 × 1 + 2 × 2 + 4 × 3 + 5 × 4 ) + ( 0 × 0 + 1 × 1 + 3 × 2 + 4 × 3 ) = 56 (1 \times 1 + 2 \times 2 + 4 \times 3 + 5 \times 4) + (0 \times 0 + 1 \times 1 + 3 \times 2 + 4 \times 3) = 56 (1×1+2×2+4×3+5×4)+(0×0+1×1+3×2+4×3)=56
为了加深理解,我们实现一下多输入通道互相关运算。 简而言之,我们所做的就是对每个通道执行互相关操作,然后将结果相加。
import torch
from d2l import torch as d2l
def corr2d_multi_in(X, K):
#先遍历 'X' 和 'K' 的第0个维度(通道维度),再把她们加在一起
return sum(d2l.corr2d(x, k) for x,k in zip(X,K))
我们可以构造与上图中的值相对应的输入张量X和核张量K,以验证互相关运算的输出。
X = torch.tensor([[[0,1,2], [3,4,5], [6,7,8]],
[[1,2,3], [4,5,6], [7,8,9]]])
K = torch.tensor([[[0,1], [2,3]], [[1,2], [3,4]]])
Y = corr2d_multi_in(X, K)
X.shape, K.shape, Y.shape, Y
(torch.Size([2, 3, 3]),
torch.Size([2, 2, 2]),
torch.Size([2, 2]),
tensor([[ 56., 72.],
[104., 120.]]))
多输出通道
到目前为止,不论有多少输入通道,我们还只有一个输出通道。然而,正如我们在之前中所讨论的,每一层有多个输出通道是至关重要的。在最流行的神经网络架构中,随着神经网络层数的加深,我们常会增加输出通道的维数,通过减少空间分辨率以获得更大的通道深度。
直观地说,我们可以将每个通道看作是对不同特征的响应。而现实可能更为复杂一些,因为每个通道不是独立学习的,而是为了共同使用而优化的。因此,多输出通道并不仅是学习多个单通道的检测器。
用 c i c_i ci 和 c o c_o co 分别表示输入和输出通道的数目,并让 k h k_h kh 和 k w k_w kw 为卷积核的高度和宽度。为了获得多个通道的输出,我们可以为每个输出通道创建一个形状为 c i × k h × k w c_i \times k_h \times k_w ci×kh×kw 的卷积核张量,这样卷积核的形状是 c o × c i × k h × k w c_o \times c_i \times k_h \times k_w co×ci×kh×kw。 在互相关运算中,每个输出通道先获取所有输入通道,再以对应该输出通道的卷积核计算出结果。
如下所示,我们实现一个计算多个通道的输出的互相关函数。
def corr2d_multi_in_out(X, K):
#执行迭代'K'的第0个维度,每次都对输入'X'执行互相关运算
#最后将所有结果都叠加在一起
return torch.stack([corr2d_multi_in(X, k) for k in K], 0)
通过将核张量K与K+1(K中每个元素加 1 1 1 )和K+2连接起来,构造了一个具有个 3 3 3 输出通道的卷积核。
K = torch.stack((K, K+1, K+2), 0)
K.shape
torch.Size([3, 2, 2, 2])
X.shape
torch.Size([2, 3, 3])
new_Y = corr2d_multi_in_out(X, K)
new_Y
tensor([[[ 56., 72.],
[104., 120.]],
[[ 76., 100.],
[148., 172.]],
[[ 96., 128.],
[192., 224.]]])
1 × 1 1 \times 1 1×1 卷积层
1 × 1 1 \times 1 1×1 卷积,即 k h = k w = 1 k_h = k_w = 1 kh=kw=1,看起来似乎没有多大意义。 毕竟,卷积的本质是有效提取相邻像素间的相关特征,而 1 × 1 1 \times 1 1×1 卷积显然没有此作用。 尽管如此, 1 × 1 1 \times 1 1×1 仍然十分流行,经常包含在复杂深层网络的设计中。下面,让我们详细地解读一下它的实际作用。
因为使用了最小窗口, 1 × 1 1 \times 1 1×1 卷积失去了卷积层的特有能力——在高度和宽度维度上,识别相邻元素间相互作用的能力。 其实 1 × 1 1 \times 1 1×1 卷积的唯一计算发生在通道上。
下图展示了使用 1 × 1 1 \times 1 1×1 卷积核与 3 3 3 个输入通道和 2 2 2 个输出通道的互相关计算。 这里输入和输出具有相同的高度和宽度,输出中的每个元素都是从输入图像中同一位置的元素的线性组合。 我们可以将 1 × 1 1 \times 1 1×1 卷积层看作是在每个像素位置应用的全连接层,以 c i c_i ci 个输入值转换为 c o c_o co 个输出值。 因为这仍然是一个卷积层,所以跨像素的权重是一致的。 同时, 1 × 1 1 \times 1 1×1 卷积层需要的权重维度为 c o × c i c_o \times c_i co×ci ,再额外加上一个偏置。
下面,我们使用全连接层实现 1 × 1 1 \times 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)) #调整X的形状为 (通道输入,像素展开乘积)
K = K.reshape((c_o, c_i)) #调整卷积核K的形状为 (输出通道,输入通道)
#全连接层的矩阵乘法
Y = torch.matmul(K, X)
return Y.reshape((c_o, h, w))
当执行 1 × 1 1 \times 1 1×1 卷积运算时,上述函数相当于先前实现的互相关函数corr2d_multi_in_out。让我们用一些样本数据来验证这一点。
X = torch.normal(0, 1, (3, 3, 3))
K = torch.normal(0, 1, (2, 3, 1, 1))
Y1 = corr2d_multi_in_out(X, K)
Y2 = corr2d_multi_in_out_1x1(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
Y1, Y2, torch.abs(Y1 - Y2)
(tensor([[[-0.7878, 0.4162, -1.8020],
[-0.4600, 0.8234, -1.3302],
[-0.9078, 1.1143, 1.0968]],
[[ 0.1313, -0.0711, -1.4497],
[-0.8206, 0.3438, 0.9701],
[ 1.8697, 0.1318, -0.6335]]]),
tensor([[[-0.7878, 0.4162, -1.8020],
[-0.4600, 0.8234, -1.3302],
[-0.9078, 1.1143, 1.0968]],
[[ 0.1313, -0.0711, -1.4497],
[-0.8206, 0.3438, 0.9701],
[ 1.8697, 0.1318, -0.6335]]]),
tensor([[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]],
[[0., 0., 0.],
[0., 0., 0.],
[0., 0., 0.]]]))
小结
-
多输入多输出通道可以用来扩展卷积层的模型。
-
当以每像素为基础应用时, 1 × 1 1 \times 1 1×1 卷积层相当于全连接层。
-
1 × 1 1 \times 1 1×1 卷积层通常用于调整网络层的通道数量和控制模型复杂性。