前言
先关资料来源于 李沐,在学习过程,记录为笔记,用于自学。
卷积神经网络可视化(帮助理解CNN原理):CNN explainer
1、不变性
假设我们想从一张图片中找到某个物体。这个物体的本身特征是不会变的,当然,它在图片中的位置是可变的。
- **平移不变性:**不管检测对象出现在图像中的哪个位置,神经网络的前面几层应该对相同的图像区域具有相似的反应,即为“平移不变性”。
- **局部性:**神经网络的前面几层应该只探索输入图像中的局部区域,而不过度在意图像中相隔较远区域的关系,这就是“局部性”原则。最终,可以聚合这些局部特征,以在整个图像级别进行预测。
- 李沐
2、多层感知机的限制
多层感知机的输入是二维图像
X
\mathbf{X}
X,其隐藏表示
H
\mathbf{H}
H在数学上是一个矩阵,在代码中表示为二维张量。其中
X
\mathbf{X}
X和
H
\mathbf{H}
H具有相同的形状。
使用
[
X
]
i
,
j
[\mathbf{X}]_{i, j}
[X]i,j和
[
H
]
i
,
j
[\mathbf{H}]_{i, j}
[H]i,j分别表示输入图像和隐藏表示中位置(
i
i
i,
j
j
j)处的像素。
为了使每个隐藏神经元都能接收到每个输入像素的信息,我们将参数从权重矩阵(如同我们先前在多层感知机中所做的那样)替换为四阶权重张量
W
\mathsf{W}
W。
那么全连接层就可以表示为:
[
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} \left[\mathbf{H}\right]_{i, j} &= [\mathbf{U}]_{i, j} + \sum_k \sum_l[\mathsf{W}]_{i, j, k, l} [\mathbf{X}]_{k, l}\\ &= [\mathbf{U}]_{i, j} + \sum_a \sum_b [\mathsf{V}]_{i, j, a, b} [\mathbf{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.
从
W
\mathsf{W}
W到
V
\mathsf{V}
V的转换只是形式上的转换,因为在这两个四阶张量的元素之间存在一一对应的关系。
只需重新索引下标
(
k
,
l
)
(k, l)
(k,l),使
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
[\mathsf{V}]_{i, j, a, b} = [\mathsf{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通过在正偏移和负偏移之间移动覆盖了整个图像。
对于隐藏表示中任意给定位置(
i
i
i,
j
j
j)处的像素值
[
H
]
i
,
j
[\mathbf{H}]_{i, j}
[H]i,j,可以通过在
x
x
x中以
(
i
,
j
)
(i, j)
(i,j)为中心对像素进行加权求和得到,加权使用的权重为
[
V
]
i
,
j
,
a
,
b
[\mathsf{V}]_{i, j, a, b}
[V]i,j,a,b。
平移不变性
检测对象在输入
X
\mathbf{X}
X中的平移,应该仅导致隐藏表示
H
\mathbf{H}
H中的平移。
V
\mathsf{V}
V和
U
\mathbf{U}
U实际上不依赖于
(
i
,
j
)
(i, j)
(i,j)的值,即
[
V
]
i
,
j
,
a
,
b
=
[
V
]
a
,
b
[\mathsf{V}]_{i, j, a, b} = [\mathbf{V}]_{a, b}
[V]i,j,a,b=[V]a,b。并且
U
\mathbf{U}
U是一个常数,比如
u
u
u。
[
H
]
i
,
j
=
u
+
∑
a
∑
b
[
V
]
a
,
b
[
X
]
i
+
a
,
j
+
b
.
[\mathbf{H}]_{i, j} = u + \sum_a\sum_b [\mathbf{V}]_{a, b} [\mathbf{X}]_{i+a, j+b}.
[H]i,j=u+a∑b∑[V]a,b[X]i+a,j+b.
在使用系数
[
V
]
a
,
b
[\mathbf{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
[\mathbf{H}]_{i, j}
[H]i,j。
注意,
[
V
]
a
,
b
[\mathbf{V}]_{a, b}
[V]a,b的系数比
[
V
]
i
,
j
,
a
,
b
[\mathsf{V}]_{i, j, a, b}
[V]i,j,a,b少很多,因为前者不再依赖于图像中的位置。这就是显著的进步!
局部性
为了收集用来训练参数 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j的相关信息,我们不应偏离到距 ( i , j ) (i, j) (i,j)很远的地方。这意味着在 ∣ a ∣ > Δ |a|> \Delta ∣a∣>Δ或 ∣ b ∣ > Δ |b| > \Delta ∣b∣>Δ的范围之外,我们可以设置 [ V ] a , b = 0 [\mathbf{V}]_{a, b} = 0 [V]a,b=0。因此,我们可以将 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j重写为
[
H
]
i
,
j
=
u
+
∑
a
=
−
Δ
Δ
∑
b
=
−
Δ
Δ
[
V
]
a
,
b
[
X
]
i
+
a
,
j
+
b
.
[\mathbf{H}]_{i, j} = u + \sum_{a = -\Delta}^{\Delta} \sum_{b = -\Delta}^{\Delta} [\mathbf{V}]_{a, b} [\mathbf{X}]_{i+a, j+b}.
[H]i,j=u+a=−Δ∑Δb=−Δ∑Δ[V]a,b[X]i+a,j+b.
上面就是一个卷积层(convolutional layer),而卷积神经网络是包含卷积层的一类特殊的神经网络。
3、卷积
简要回顾一下为什么上面的操作被称为卷积。在数学中,两个函数(比如 f , g : R d → R f, g: \mathbb{R}^d \to \mathbb{R} f,g:Rd→R)之间的“卷积”被定义为
( f ∗ g ) ( x ) = ∫ f ( z ) g ( x − z ) d z . (f * g)(\mathbf{x}) = \int f(\mathbf{z}) g(\mathbf{x}-\mathbf{z}) d\mathbf{z}. (f∗g)(x)=∫f(z)g(x−z)dz.
也就是说,卷积是当把一个函数“翻转”并移位
x
\mathbf{x}
x时,测量
f
f
f和
g
g
g之间的重叠。
当为离散对象时,积分就变成求和。例如,对于由索引为
Z
\mathbb{Z}
Z的、平方可和的、无限维向量集合中抽取的向量,我们得到以下定义:
( f ∗ g ) ( i ) = ∑ a f ( a ) g ( i − a ) . (f * g)(i) = \sum_a f(a) g(i-a). (f∗g)(i)=a∑f(a)g(i−a).
对于二维张量,则为 f f f的索引 ( a , b ) (a, b) (a,b)和 g g g的索引 ( i − a , j − b ) (i-a, j-b) (i−a,j−b)上的对应加和:
(
f
∗
g
)
(
i
,
j
)
=
∑
a
∑
b
f
(
a
,
b
)
g
(
i
−
a
,
j
−
b
)
.
(f * g)(i, j) = \sum_a\sum_b f(a, b) g(i-a, j-b).
(f∗g)(i,j)=a∑b∑f(a,b)g(i−a,j−b).
有一个主要区别:这里不是使用
(
i
+
a
,
j
+
b
)
(i+a, j+b)
(i+a,j+b),而是使用差值。
4、互相关运算和卷积运算
- 互相关运算
[ H ] i , j = u + ∑ a = − Δ Δ ∑ b = − Δ Δ [ V ] a , b [ X ] i + a , j + b . [\mathbf{H}]_{i, j} = u + \sum_{a = -\Delta}^{\Delta} \sum_{b = -\Delta}^{\Delta} [\mathbf{V}]_{a, b} [\mathbf{X}]_{i+a, j+b}. [H]i,j=u+a=−Δ∑Δb=−Δ∑Δ[V]a,b[X]i+a,j+b. - 卷积运算
( f ∗ g ) ( i , j ) = ∑ a ∑ b f ( a , b ) g ( i − a , j − b ) . (f * g)(i, j) = \sum_a\sum_b f(a, b) g(i-a, j-b). (f∗g)(i,j)=a∑b∑f(a,b)g(i−a,j−b).
如果想要执行卷积运算,就需要对上面互相关运算的卷积核张量进行水平和垂直的翻转,然后进行互相关运算。
简而言之,
卷积运算 = 卷积核水平和垂直翻转 + 互相关运算 卷积运算 = 卷积核水平和垂直翻转 + 互相关运算 卷积运算=卷积核水平和垂直翻转+互相关运算
但是,无论这些层执行严格的卷积运算还是互相关运算,卷积层的输出都不会受到影响。
所以,为了方便,我们就把互相关运算叫做卷积运算。本质是没有什么区别的。
5、填充和步幅
- 填充: 添加 p h p_h ph行填充(大约一半在顶部,一半在底部)和 p w p_w pw列填充(左侧大约一半,右侧一半),则输出形状将为
(
n
h
−
k
h
+
p
h
+
1
)
×
(
n
w
−
k
w
+
p
w
+
1
)
。
(n_h-k_h+p_h+1)\times(n_w-k_w+p_w+1)。
(nh−kh+ph+1)×(nw−kw+pw+1)。
需要设置
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
核为奇数,上下左右填充
p
/
2
p/2
p/2。
核为偶数,上下左右可以不均匀的填充,不对称没啥影响。
- 步幅: 当垂直步幅为 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 ⌋ . \lfloor(n_h-k_h+p_h+s_h)/s_h\rfloor \times \lfloor(n_w-k_w+p_w+s_w)/s_w\rfloor. ⌊(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
⌋
\lfloor(n_h+s_h-1)/s_h\rfloor \times \lfloor(n_w+s_w-1)/s_w\rfloor
⌊(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)。
6、多输入输出通道
- 多输入通道:
当 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的结果相加)得到二维张量。这是多通道输入和多输入通道卷积核之间进行二维互相关运算的结果。
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))
# zip对输入数据最外层的那个维度打包成元组,遍历也是从最外层那个维度做遍历。
- 多输出通道:
不同的输出通道看做不同特征的响应。每个通道不是独立学习的,而是为了共同使用而优化的。
用 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。
7、计算复杂度
8、汇聚层(池化层)
- 汇聚层的作用:
- 降低卷积层对位置的敏感性
- 降低对空间降采样的敏感性
- 最大汇聚层
- 汇聚窗口中所有元素的最大值
- 平均汇聚层
- 汇聚窗口中所有元素的平均值
- 汇聚窗口中所有元素的平均值