目录
- 多个输入通道
- 多个输出通道
- 多个输入和输出通道
- 1×1卷积层
- 二维卷积层
- 总结
- 多输入多输出通道代码实现
- 多输入单输出通道代码实现
- 多输出通道代码实现
- 该部分代码
- 多输入多输出通道总代码
- 多个输入和输出通道用途
- 1×1卷积
- 该部分总代码
- 问题
多个输入通道
彩色图像可能有RGB三个通道
转换为灰度会丢失信息。
每个通道都有一个卷积核,结果是所有通道卷积结果的和。
输入有2个通道(通道0、通道1),对每一个通道都有一个卷积核。
c
i
c_i
ci是通道,输入是三维的。核也是三维。
多个输出通道
无论有多少输入通道,到目前为止我们只用到单输出通道。
我们可以有多个三维卷积核,每个核生成一个输出通道。
c
o
c_o
co其实就是
c
o
u
t
p
u
t
c_{output}
coutput,
c
i
c_i
ci个通道,每个通道
c
o
c_o
co种卷积核,共有
c
i
c_i
ci*
c
o
c_o
co种卷积核。
c
i
c_i
ci:输入通道的(卷积核)层数
c
o
c_o
co:输出通道(卷积核)层数
为了提出不同的特征,两者无相关性。
多个输入和输出通道
每个输出通道可以识别特定模式。
输入通道核识别并组合输入中的模式。
1×1卷积层
k h k_h kh= k w k_w kw=1是一个受欢迎的选择。它不识别空间模式,只是融合通道。
通道0和通道1的卷积核
把output对应输入里面的像素,每个不同的通道做加权和。
相当于输入形状为
n
h
n_ h
nh
n
w
n_ w
nw×
c
i
c_ i
ci(把输入拉成一个
n
h
n_ h
nh
n
w
n_ w
nw向量,列数是
c
i
c_ i
ci,整体是一个矩阵),权重为
c
i
c_ i
ci×
c
o
c_ o
co的全连接层。
二维卷积层
一共有
c
o
c_ o
co×
c
i
c_ i
ci个卷积核,每个卷积核都有一个偏差。
计算复杂度:
这么理解:最后输出
m
h
m_ h
mh×
m
w
m_ w
mw个点,有
c
o
c_ o
co个通道,这意味着总共有
c
o
c_ o
co×
m
h
m_ h
mh×
m
w
m_ w
mw个输出点,对于每个输出点,它都涉及到与卷积核的乘法操作。卷积核的大小为
k
h
k_h
kh×
k
w
k_w
kw,且输入特征图有
c
i
c_ i
ci个通道,那么对于输出特征图上的每一个点,都需要进行
c
i
c_ i
ci×
k
h
k_h
kh×
k
w
k_w
kw次乘法操作。(因为每个输出点都是输入特征图上对应区域的
c
i
c_i
ci个通道与卷积核的乘积之和)。
总结
①输入通道数是卷积层的超参数。
②每个输入通道都有独立的二维卷积核,所有通道结果相加得到一个输出通道结果。
③每个输出通道有独立的三维卷积核。
多输入多输出通道代码实现
多输入单输出通道代码实现
实现一下多输入通道互相关运算
import torch
from d2l import torch as d2l
def corr2d_multi_in(X, K):
# for使得对最外面通道进行遍历,先遍历“X”和“K”的第0个维度(通道维度)
# 使用sum 函数来遍历 X 和 K 的通道,并对每个通道对应用 d2l.corr2d 函数进行二维卷积操作,然后将所有通道的结果相加。
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))
输出:
多输出通道代码实现
计算多个通道的输出的互相关函数
def corr2d_multi_in_out(X, K):
# 迭代“K”的第0个维度(输出通道),每次都对输入“X”执行互相关运算。
# 最后将所有结果都叠加在一起
# torch.stack([...], 0) 将上一步生成的列表中的张量沿着一个新的维度(这里是第0维,即批量大小维度)堆叠起来
return torch.stack([corr2d_multi_in(X, k) for k in K], 0)
通过将核张量K与K+1(K中每个元素加1)和K+2连接起来,构造了一个具有3个输出通道的卷积核。
# 要堆叠的张量K、K+1、K+2
# K原来是3D,然后通过stack堆叠成为4D
K = torch.stack((K, K + 1, K + 2), 0)
print(K.shape)
输出:输出是3,输入是2,高和宽分别是2(3个卷积核,每个卷积核有两个通道,每个通道是2×2的矩阵)
①为什么原先K形状是torch.Size([2, 2, 2]),后来变成了torch.Size([3, 2, 2, 2])?
三个堆起来就是最外层3.
②输入为什么是2?
因为X的通道是2
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、K+1、K+2(左),后来堆叠的(右)
该部分代码
import torch
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]]])
print(X.shape)
K = torch.tensor([[[0.0, 1.0], [2.0, 3.0]], [[1.0, 2.0], [3.0, 4.0]]])
print(K.shape) # torch.Size([2, 2, 2]) 两块2行2列
print(K)
print(K+1)
print(K+2)
K = torch.stack((K, K + 1, K + 2), 0)
print(K)
print(K.shape)
对输入张量X与卷积核张量K执行互相关运算。现在的输出包含3个通道,第一个通道的结果与先前输入张量X和多输入单输出通道的结果一致。
corr2d_multi_in_out(X, K)
多输入多输出通道总代码
import torch
from d2l import torch as d2l
def corr2d_multi_in(X, K):
# for使得对最外面通道进行遍历,先遍历“X”和“K”的第0个维度(通道维度)
# 使用sum 函数来遍历 X 和 K 的通道,并对每个通道对应用 d2l.corr2d 函数进行二维卷积操作,然后将所有通道的结果相加。
return sum(d2l.corr2d(x, k) for x, k in zip(X, K))
def corr2d_multi_in_out(X, K):
# 迭代“K”的第0个维度(输出通道),每次都对输入“X”执行互相关运算。
# 最后将所有结果都叠加在一起
# torch.stack([...], 0) 将上一步生成的列表中的张量沿着一个新的维度(这里是第0维,即批量大小维度)堆叠起来
return torch.stack([corr2d_multi_in(X,k) for k in K],0) # 大k中每个小k是一个3D的Tensor。0表示stack堆叠函数里面在0这个维度堆叠。
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]]])
K = torch.stack((K, K + 1, K + 2), 0)
print(corr2d_multi_in_out(X, K))
输出:
多个输入和输出通道用途
①每个输出通道可以识别特定模式
②输入通道核识别并组合输入中的模式
1×1卷积
k h k_h kh= k w k_w kw=1。它不识别空间模式,只是融合通道。相当于输入形状为 n h n_h nh n w n_w nw× c i c_i ci,权重为 c o c_o co× c i c_i ci的全连接层。
下面,我们使用全连接层实现 1×1 卷积。 请注意,我们需要对输入和输出的数据形状进行调整。
def corr2d_multi_in_out_1x1(X, K):
# 获取输入X的形状,其中c_i是输入通道数,h是高度,w是宽度
c_i, h, w = X.shape
# 获取卷积核K的形状,其中c_o是输出通道数
c_o = K.shape[0]
# 将二维的图像数据(高度和宽度)平铺成一维
X = X.reshape((c_i, h * w))
# # 将卷积核K的形状保持不变,因为对于1x1卷积,卷积核的形状已经是(c_o, c_i)
K = K.reshape((c_o, c_i))
# 全连接层中的矩阵乘法
Y = torch.matmul(K, X)
# 将矩阵乘法的结果Y的形状从(c_o, h*w)重塑为(c_o, h, w)
# 即将一维的输出数据恢复成二维的图像数据(高度和宽度),同时保持输出通道数c_o
return Y.reshape((c_o, h, w))
当执行 1×1 卷积运算时,上述函数相当于先前实现的互相关函数corr2d_multi_in_out。让我们用一些样本数据来验证这一点。
# (3, 3, 3)第一个3是3个通道数,后面两个3是高和宽
X = torch.normal(0, 1, (3, 3, 3))
# (2, 3, 1, 1)第一个参数2是输出,第二个参数是输入通道3,后面两个参数是高和宽,kernel数是1×1
K = torch.normal(0, 1, (2, 3, 1, 1))
Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
# 意味着1×1的卷积层相当于输入形状为c_i × n_hn_w,权重为c_o × c_i的全连接层
该部分总代码
import torch
from d2l import torch as d2l
def corr2d_multi_in(X, K):
# for使得对最外面通道进行遍历,先遍历“X”和“K”的第0个维度(通道维度)
# 使用sum 函数来遍历 X 和 K 的通道,并对每个通道对应用 d2l.corr2d 函数进行二维卷积操作,然后将所有通道的结果相加。
return sum(d2l.corr2d(x, k) for x, k in zip(X, K))
def corr2d_multi_in_out(X, K):
# 迭代“K”的第0个维度(输出通道),每次都对输入“X”执行互相关运算。
# 最后将所有结果都叠加在一起
# torch.stack([...], 0) 将上一步生成的列表中的张量沿着一个新的维度(这里是第0维,即批量大小维度)堆叠起来
return torch.stack([corr2d_multi_in(X, k) for k in K], 0) # 大k中每个小k是一个3D的Tensor。0表示stack堆叠函数里面在0这个维度堆叠。
def corr2d_multi_in_out_1x1(X, K):
# 获取输入X的形状,其中c_i是输入通道数,h是高度,w是宽度
c_i, h, w = X.shape
# 获取卷积核K的形状,其中c_o是输出通道数
c_o = K.shape[0]
# 将二维的图像数据(高度和宽度)平铺成一维
X = X.reshape((c_i, h * w))
# # 将卷积核K的形状保持不变,因为对于1x1卷积,卷积核的形状已经是(c_o, c_i)
K = K.reshape((c_o, c_i))
# 全连接层中的矩阵乘法
Y = torch.matmul(K, X)
# 将矩阵乘法的结果Y的形状从(c_o, h*w)重塑为(c_o, h, w)
# 即将一维的输出数据恢复成二维的图像数据(高度和宽度),同时保持输出通道数c_o
return Y.reshape((c_o, h, w))
# (3, 3, 3)第一个3是3个通道数,后面两个3是高和宽
X = torch.normal(0, 1, (3, 3, 3))
# (2, 3, 1, 1)第一个参数2是输出,第二个参数是输入通道3,后面两个参数是高和宽,kernel数是1×1
K = torch.normal(0, 1, (2, 3, 1, 1))
Y1 = corr2d_multi_in_out_1x1(X, K)
Y2 = corr2d_multi_in_out(X, K)
print(Y1.shape)
print(Y2.shape)
print(Y1)
print(Y2)
assert float(torch.abs(Y1 - Y2).sum()) < 1e-6
# 意味着1×1的卷积层相当于输入形状为c_i × n_hn_w,权重为c_o × c_i的全连接层
print(float(torch.abs(Y1-Y2).sum()))
输出:
问题
①网络越深,Padding 0越多,这里是否会影响性能?
0不会影响性能。
②⭐每个通道的卷积核都不一样吗?不同通道的卷积核大小必须一样吗?
每个通道的卷积核是不一样的,因为有多少个输出通道就有多少种卷积核。
不同通道的卷积核是一样的,(这是因为计算上的好处,如果不一样的话得写成两个卷积操作。)即:不同通道的同一个输出通道的卷积核是一样的。
③计算卷积时,bias的有无,对结果影响大吗?bias的作用怎么解释?
偏移是有一些用的。但没那么大的影响。
④核的参数是学出来的,不是选出来的。
⑤如果是一个RGB图像,加上深度图,相当于输入是四个通道,做卷积是和RGB三通道同样做法吗?
不是,这地方介绍的二维卷积(只有高宽两个channel),如果加上深度这个维度,就用3D卷积。3D卷积同样有一个输入输出通道。输入就会变成:输入通道×深度×宽×高(4D),核会变成5D的张量,输出同样也是4D.