李沐《动手学深度学习》卷积神经网络 相关基础概念
系列文章
李沐《动手学深度学习》预备知识 张量操作及数据处理
李沐《动手学深度学习》预备知识 线性代数及微积分
李沐《动手学深度学习》线性神经网络 线性回归
李沐《动手学深度学习》线性神经网络 softmax回归
李沐《动手学深度学习》多层感知机 模型概念和代码实现
李沐《动手学深度学习》多层感知机 深度学习相关概念
李沐《动手学深度学习》深度学习计算
目录
教材:李沐《动手学深度学习》
卷积神经网络(convolutional neural network,CNN)是一类强大的、为处理图像数据而设计的神经网络,是机器学习利用自然图像中一些已知结构的创造性方法。
一、从全连接层到卷积
(一)全连接层
-
全连接层网络的缺点:
- 不能预先假设任何与特征交互相关的先验结构;
- 全连接层往往意味着大量的参数,需要大量的GPU、分布式优化训练的经验和超乎常人的耐心。
-
全连接层的形式化表示:( X X X是输入的二维图像, H H H是其对应的隐藏表示, W W W是权重矩阵, U U U包含偏置参数)
[ H ] i , j = [ U ] i , j + ∑ k ∑ l [ W ] i , j , k , l [ X ] k , l = [ U ] i , j + ∑ a ∑ b [ V ] i , j , a , b [ X ] i + a , j + b \begin{aligned} [H]_{i,j} &=[U]_{i,j}+\sum_{k}\sum_{l}[W]_{i,j,k,l}[X]_{k,l}\\ &=[U]_{i,j}+\sum_{a}\sum_{b}[V]_{i,j,a,b}[X]_{i+a,j+b} \end{aligned} [H]i,j=[U]i,j+k∑l∑[W]i,j,k,l[X]k,l=[U]i,j+a∑b∑[V]i,j,a,b[X]i+a,j+b
令 k = i + a k=i+a k=i+a, l = j + b l=j+b l=j+b,则有 [ V ] i , j , a , b = [ W ] i , j , i + a , j + b [V]_{i,j,a,b}=[W]_{i,j,i+a,j+b} [V]i,j,a,b=[W]i,j,i+a,j+b。索引 a a a和 b b b在正偏移和负偏移之间移动覆盖了整个图像。
(二)卷积神经网络的空间不变性
-
平移不变性: 不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应;(这意味着检测对象在输入 X X X中的平移仅导致隐藏表示 H H H中的平移,而 V V V和 U U U实际上不依赖于 ( i , j ) (i,j) (i,j)的值)
[ H ] i , j = u + ∑ a ∑ b [ V ] a , b [ X ] i + a , j + b [H]_{i,j}=u+\sum_{a}\sum_{b}[V]_{a,b}[X]_{i+a,j+b} [H]i,j=u+a∑b∑[V]a,b[X]i+a,j+b
这就是卷积: 使用系数 [ V ] a , b [V]_{a,b} [V]a,b对位置 ( i , j ) (i,j) (i,j)附近的像素 ( i + a , j + b ) (i+a,j+b) (i+a,j+b)进行加权得到 [ H ] i , j [H]_{i,j} [H]i,j,而且此时 [ V ] a , b [V]_{a,b} [V]a,b的系数比 [ V ] i , j , a , b [V]_{i,j,a,b} [V]i,j,a,b少很多,因为前者不再依赖于图像中的位置。 -
局部性: 神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终,可以聚合这些局部特征,以在整个图像级别进行预测。(在 ∣ a ∣ > Δ |a| > \Delta ∣a∣>Δ或 ∣ b ∣ > Δ |b| > \Delta ∣b∣>Δ的范围之外,可以设置 [ V ] a , b = 0 [V]_{a,b}=0 [V]a,b=0)
[ H ] i , j = u + ∑ a = − Δ Δ ∑ b = − Δ Δ [ V ] a , b [ X ] i + a , j + b [H]_{i,j}=u+\sum_{a=-\Delta}^\Delta\sum_{b=-\Delta}^\Delta[V]_{a,b}[X]_{i+a,j+b} [H]i,j=u+a=−Δ∑Δb=−Δ∑Δ[V]a,b[X]i+a,j+b
这就是卷积层: V V V被称为卷积核或滤波器,也就是卷积层的权重。 -
卷积的本质是有效提取相邻像素间的相关特征。
(三)通道
实际上,图像不是二维张量,而是一个由高度、宽度和颜色组成的三维张量。
[
H
]
i
,
j
,
d
=
∑
a
=
−
Δ
Δ
∑
b
=
−
Δ
Δ
∑
c
[
V
]
a
,
b
,
c
,
d
[
X
]
i
+
a
,
j
+
b
,
c
[H]_{i,j,d}=\sum_{a=-\Delta}^\Delta\sum_{b=-\Delta}^\Delta\sum_{c}[V]_{a,b,c,d}[X]_{i+a,j+b,c}
[H]i,j,d=a=−Δ∑Δb=−Δ∑Δc∑[V]a,b,c,d[X]i+a,j+b,c
这是具有多个通道的卷积层,其中
V
V
V是该卷积层的权重。
二、图像卷积
(一)互相关运算
- 在卷积层中,输入张量和核张量通过互相关运算产生输出张量;
- 输出大小等于输入大小
n
h
×
n
w
n_h\times n_w
nh×nw减去卷积核大小
k
h
×
k
w
k_h \times k_w
kh×kw,即:
( n h − k h + 1 ) × ( n w − k w + 1 ) (n_h-k_h+1)\times(n_w-k_w+1) (nh−kh+1)×(nw−kw+1)
二维互相关运算的实现:
def corr2d(X, K): #@save
"""计算二维互相关运算"""
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i + h, j:j + w] * K).sum()
return Y
(二)卷积层
- 卷积层对输入和卷积核权重进行互相关运算,并在添加标量偏置之后产生输出。 所以,卷积层中的两个被训练的参数是卷积核权重和标量偏置。 在训练基于卷积层的模型时,会随机初始化卷积核权重。
二维卷积层的实现:
class Conv2D(nn.Module):
def __init__(self, kernel_size):
super().__init__()
self.weight = nn.Parameter(torch.rand(kernel_size))
self.bias = nn.Parameter(torch.zeros(1))
def forward(self, x):
return corr2d(x, self.weight) + self.bias
- 卷积层的一个简单应用:通过找到像素变化的位置,来检测图像中不同颜色的边缘,实现图像中目标的边缘检测。
(三)学习卷积核
先构造一个卷积层,并将其卷积核初始化为随机张量。接下来,在每次迭代中,我们比较Y与卷积层输出的平方误差,然后计算梯度来更新卷积核。
# 构造一个二维卷积层,它具有1个输出通道和形状为(1,2)的卷积核
conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)
# 这个二维卷积层使用四维输入和输出格式(批量大小、通道、高度、宽度),
# 其中批量大小和通道数都为1
X = X.reshape((1, 1, 6, 8))
Y = Y.reshape((1, 1, 6, 7))
lr = 3e-2 # 学习率
for i in range(10):
Y_hat = conv2d(X)
l = (Y_hat - Y) ** 2
conv2d.zero_grad()
l.sum().backward()
# 迭代卷积核
conv2d.weight.data[:] -= lr * conv2d.weight.grad
if (i + 1) % 2 == 0:
print(f'epoch {i+1}, loss {l.sum():.3f}')
(四)特征映射和感受野
- 特征映射:卷积层有时被称为特征映射,因为它可以被视为一个输入映射到下一层的空间维度的转换器;
- 感受野:在卷积神经网络中,对于某一层的任意元素 x x x,其感受野是指在前向传播期间可能影响计算的所有元素(来自所有先前层)。
三、填充和步幅
填充和步幅可用于有效地调整数据的维度
(一)填充:在输入图像的边界填充元素(通常填充元素是0)
- 填充可以增加输出的高度和宽度,这常用来使输出与输入具有相同的高和宽;
- 如果我们添加
p
h
p_h
ph行填充(大约一半在顶部,一半在底部)和列填充
p
w
p_w
pw(左侧大约一半,右侧一半),则输出形状将为
( n h + p h − k h + 1 ) × ( n w + p w − k w + 1 ) (n_h+p_h-k_h+1)\times(n_w+p_w-k_w+1) (nh+ph−kh+1)×(nw+pw−kw+1)
此时输出的高度和宽度将分别增加和 p h p_h ph和 p w p_w pw; - 如果要使得输入和输出具有相同的高度和宽度,则应该设置 p h = k h − 1 p_h=k_h-1 ph=kh−1和 p w = k w − 1 p_w=k_w-1 pw=kw−1,如果 k h k_h kh是奇数,则应该在高度的两侧填充 p h / 2 p_h/2 ph/2行,如果 k h k_h kh是偶数,则应该在输入的顶部填充 [ p h / 2 ] [p_h/2] [ph/2]行,在底部填充 [ p h / 2 ] [p_h/2] [ph/2]行。因此卷积神经网络中卷积核的高度和宽度通常为奇数,在保持空间维度的同时,可以在顶部和底部填充相同数量的行,在左侧和右侧填充相同数量的列。
卷积层高度和宽度均为3,所有侧边填充1个像素(padding=1)
import torch
from torch import nn
# 为了方便起见,我们定义了一个计算卷积层的函数。
# 此函数初始化卷积层权重,并对输入和输出提高和缩减相应的维数
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列
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1)
X = torch.rand(size=(8, 8))
comp_conv2d(conv2d, X).shape
卷积层高度为5,宽度为3,高度和宽度两边的填充分别为2和1(padding=(2,1))
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1))
comp_conv2d(conv2d, X).shape
(二)步幅:每次滑动元素的数量
- 步幅可以减小输出的高和宽,例如输出的高和宽仅为输入的高和宽的 1 n \frac{1}{n} n1(n是一个大于1的整数);
- 当垂直步幅为
s
h
s_h
sh、水平步幅为
s
w
s_w
sw时,输出形状为:
[ ( n h − k h + p h + s h ) / s h ] × [ n w − k w + p w + s w ) / s w ] [(n_h-k_h+p_h+s_h)/s_h]\times[n_w-k_w+p_w+s_w)/s_w] [(nh−kh+ph+sh)/sh]×[nw−kw+pw+sw)/sw]
如果设置了 p h = k h − 1 p_h=k_h-1 ph=kh−1和 p w = k w − 1 p_w=k_w-1 pw=kw−1,输出形状将简化为:
[ ( n h + s h − 1 ) / s h ] × [ n w + s w − 1 ) / s w ] [(n_h+s_h-1)/s_h]\times[n_w+s_w-1)/s_w] [(nh+sh−1)/sh]×[nw+sw−1)/sw]
如果输入的高度和宽度可以被垂直和步幅整除,则输出形状为:
( n h / s h ) × ( n w / s w ) (n_h/s_h)\times(n_w/s_w) (nh/sh)×(nw/sw)
将高度和宽度的步幅设置为2(stride=2):
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
comp_conv2d(conv2d, X).shape
四、多输入多输出通道
(一)多输入通道
- 卷积核:与输入数据具有相同输入通道数
- 多输入通道互相关运算: 对每个通道执行互相关操作,然后将结果相加
利用代码实现多输入通道的互相关计算:
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))
(二)多输出通道
-
每个通道可以看作是对不同特征的响应。每个通道不是独立学习的,而是为了共同使用而优化的,因此多输出通道并不仅是学习多个单通道的检测器。
-
为了获得多个通道的输出,可以为每个输出通道创建一个形状 c i × k h × k w c_i\times k_h \times k_w ci×kh×kw的卷积核张量,这样卷积核的形状是 c 0 × c i × k h × k w c_0\times c_i\times k_h \times k_w c0×ci×kh×kw。( c i c_i ci:输入通道数, c 0 c_0 c0:输出通道数, k h k_h kh:卷积核的高度, k w k_w kw:卷积核的宽度)
def corr2d_multi_in_out(X, K):
# 迭代“K”的第0个维度,每次都对输入“X”执行互相关运算。
# 最后将所有结果都叠加在一起
return torch.stack([corr2d_multi_in(X, k) for k in K], 0)
(三)1x1卷积层
- 1x1卷积失去了卷积层的特有能力——在高度和宽度维度上,识别相邻元素间相互作用的能力;
- 1x1卷积层通常用于调整网络层的通道数量和控制模型复杂性
- 1x1卷积的唯一计算发生在通道上;
当以每像素为基础应用时,可以将1x1卷积层看作是在每个像素位置应用的全连接层,用 c i c_i ci个输入值转换 c 0 c_0 c0个输出值;下图是使用1x1卷积核与3个输入通道和2个输出通道的互相关计算,这里的输入和输出具有相同的高度和宽度,输出中的每个元素都是从输入图像中同一位置的线性组合。
使用全连接层实现1x1卷积:
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))
五、汇聚层
当我们处理图像时,我们希望逐渐降低隐藏表示的空间分辨率、聚集信息,这样随着我们在神经网络中层叠的上升,每个神经元对其敏感的感受野(输入)就越大。通过逐渐聚合信息,生成越来越粗糙的映射,最终实现学习全局表示的目标,同时将卷积图层的所有优势保留在中间层。
- 汇聚(pooling)层的双重目的:
- 降低卷积层对位置的敏感性;
- 降低对空间降采样表示的敏感性。
- 汇聚层与卷积层的比较:
- 相同点:都是由一个固定形状的窗口组成,根据步幅大小在输入区域上滑动
- 不同点:卷积层对应互相关计算是有参数的;汇聚层的池运算是确定的,汇聚层不包含参数
- 汇聚层按照计算方法可以分为最大汇聚层和平均汇聚层,最大汇聚层返回汇聚窗口中所有元素的最大值,平均汇聚层返回汇聚窗口中所有元素的平均值;
- 与卷积层一样,汇聚层也可以改变输出形状,可以通过填充和步幅以获得所需的输出形状;
- 在处理多通道输入数据时,汇聚层在每个输入通道上单独运算,而不是像卷积层一样在通道上对输入进行汇总。 这意味着汇聚层的输出通道数与输入通道数相同
实现汇聚层的前向传播:
import torch
from torch import nn
from d2l import torch as d2l
def pool2d(X, pool_size, mode='max'):
p_h, p_w = pool_size
Y = torch.zeros((X.shape[0] - p_h + 1, X.shape[1] - p_w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
if mode == 'max':
Y[i, j] = X[i: i + p_h, j: j + p_w].max()
elif mode == 'avg':
Y[i, j] = X[i: i + p_h, j: j + p_w].mean()
return Y
原文地址:https://blog.csdn.net/weixin_47748259/article/details/135706350
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!