神经元与神经网络回顾
从high level来说,全连接神经网络从左向右依次是输入层,隐藏层和输出层。针对于一个神经元,前向操作一般是
- 输入 x i x_i xi与对应权重 w i w_i wi相乘再求和,然后加上偏置 b b b得到中间结果 z = Σ i w i x i + b z=\Sigma_{i} w_{i} x_{i}+b z=Σiwixi+b.
- 中间结果 z z z经过激活函数 f ( z ) f(z) f(z)得到输出 a = f ( z ) a=f(z) a=f(z)
- 使用 f ( z ) = 1 1 + e − z f(z)=\frac{1}{1+e^{-z}} f(z)=1+e−z1作为激活函数,它通常记作 σ ( z ) \sigma(z) σ(z)
于是我们有前向传播公式:
a
∈
R
n
×
1
,
W
∈
R
m
×
n
,
z
∈
R
m
×
1
,
b
∈
R
m
×
1
a \in R^{n \times 1}, W \in R^{m \times n}, z \in R^{\mathrm{m} \times 1}, b \in R^{m \times 1}
a∈Rn×1,W∈Rm×n,z∈Rm×1,b∈Rm×1,
z
=
W
a
+
b
=
[
w
11
⋯
w
1
n
⋮
⋱
⋮
w
m
1
⋯
w
m
n
]
⋅
[
a
1
⋮
a
n
]
+
[
b
1
⋮
b
m
]
=
[
∑
i
n
w
1
i
a
i
+
b
1
⋮
∑
i
w
m
i
a
i
+
b
m
]
z=W a+b=\left[\begin{array}{ccc} w_{11} & \cdots & w_{1 n} \\ \vdots & \ddots & \vdots \\ w_{m 1} & \cdots & w_{m n} \end{array}\right] \cdot\left[\begin{array}{c} a_{1} \\ \vdots \\ a_{n} \end{array}\right]+\left[\begin{array}{c} b_{1} \\ \vdots \\ b_{m} \end{array}\right]\\ =\left[\begin{array}{c} \sum_{i}^{n} w_{1 i} a_{i}+b_{1} \\ \vdots \\ \sum_{i} w_{m i} a_{i}+b_{m} \end{array}\right]
z=Wa+b=⎣⎢⎡w11⋮wm1⋯⋱⋯w1n⋮wmn⎦⎥⎤⋅⎣⎢⎡a1⋮an⎦⎥⎤+⎣⎢⎡b1⋮bm⎦⎥⎤=⎣⎢⎡∑inw1iai+b1⋮∑iwmiai+bm⎦⎥⎤
反向传播公式:
a
∈
R
n
×
1
,
W
∈
R
m
×
n
,
z
ˉ
∈
R
m
×
1
,
b
∈
R
m
×
1
a \in R^{n \times 1}, W \in R^{m \times n}, \bar{z} \in R^{\mathrm{m} \times 1}, b \in R^{m \times 1}
a∈Rn×1,W∈Rm×n,zˉ∈Rm×1,b∈Rm×1
∂
L
∂
a
=
W
T
⋅
∂
L
∂
z
=
[
w
11
⋯
w
m
1
⋮
⋱
⋮
w
1
n
⋯
w
m
n
]
⋅
[
∂
L
∂
z
1
⋮
∂
L
∂
z
m
]
=
[
∑
i
=
1
m
w
i
1
⋅
∂
L
∂
z
i
⋮
∑
i
=
1
m
w
i
n
⋅
∂
L
∂
z
i
]
\frac{\partial L}{\partial a}=W^{T} \cdot \frac{\partial L}{\partial z}=\left[\begin{array}{ccc} w_{11} & \cdots & w_{m 1} \\ \vdots & \ddots & \vdots \\ w_{1 n} & \cdots & w_{m n} \end{array}\right] \cdot\left[\begin{array}{c} \frac{\partial L}{\partial z_{1}} \\ \vdots \\ \frac{\partial L}{\partial z_{m}} \end{array}\right]=\left[\begin{array}{c} \sum_{i=1}^{m} w_{i 1} \cdot \frac{\partial L}{\partial z_{i}} \\ \vdots \\ \sum_{i=1}^{m} w_{i n} \cdot \frac{\partial L}{\partial z_{i}} \end{array}\right]
∂a∂L=WT⋅∂z∂L=⎣⎢⎡w11⋮w1n⋯⋱⋯wm1⋮wmn⎦⎥⎤⋅⎣⎢⎡∂z1∂L⋮∂zm∂L⎦⎥⎤=⎣⎢⎡∑i=1mwi1⋅∂zi∂L⋮∑i=1mwin⋅∂zi∂L⎦⎥⎤
∂ L ∂ W = ∂ L ∂ z ⋅ a T = [ ∂ L ∂ z 1 ⋮ ∂ L ∂ z m ] [ a 1 … a n ] = [ ∂ L ∂ z 1 ⋅ a 1 ⋯ ∂ L ∂ z 1 ⋅ a n ⋮ ⋱ ⋮ ∂ L ∂ z m ⋅ a 1 ⋯ ∂ L ∂ z m ⋅ a n ] \frac{\partial L}{\partial W}=\frac{\partial L}{\partial z} \cdot a^{T}=\left[\begin{array}{c} \frac{\partial L}{\partial z_{1}} \\ \vdots \\ \frac{\partial L}{\partial z_{m}} \end{array}\right] \begin{array}{lll} {\left[\begin{array}{lll} a_{1} & \ldots & a_{n} \end{array}\right]} \end{array}=\left[\begin{array}{lll} \frac{\partial L}{\partial z_{1}} \cdot a_{1} & \cdots & \frac{\partial L}{\partial z_{1}} \cdot a_{n} \\ \vdots & \ddots & \vdots \\ \frac{\partial L}{\partial z_{m}} \cdot a_{1} & \cdots & \frac{\partial L}{\partial z_{m}} \cdot a_{n} \end{array}\right] ∂W∂L=∂z∂L⋅aT=⎣⎢⎡∂z1∂L⋮∂zm∂L⎦⎥⎤[a1…an]=⎣⎢⎡∂z1∂L⋅a1⋮∂zm∂L⋅a1⋯⋱⋯∂z1∂L⋅an⋮∂zm∂L⋅an⎦⎥⎤
∂ L ∂ b = ∂ L ∂ z ⋅ 1 = [ ∂ L ∂ z 1 ⋮ ∂ L ∂ z m ] \frac{\partial L}{\partial b}=\frac{\partial L}{\partial z} \cdot 1=\left[\begin{array}{c} \frac{\partial L}{\partial z_{1}} \\ \vdots \\ \frac{\partial L}{\partial z_{m}} \end{array}\right] ∂b∂L=∂z∂L⋅1=⎣⎢⎡∂z1∂L⋮∂zm∂L⎦⎥⎤
全局感受野与局部感受野
对于全连接层,神经网络的隐藏神经元与前一层所有神经元全部相互连接,也就是说,一个神经元就完整的关注了前一层的一整幅图。这就造成了全连接网络的参数矩阵维度很大,巨大的参数量就导致计算资源的消耗及其庞大。 【而且全连接层对于不同的区域都连接,其实不同的区域关联性不是很强,拼凑到一起输入到下一层某个神经元其实有些牵强】
局部感受野
科学家发现人眼观察图像的时候并不是依靠全连接,每个神经元只感受局部的图像区域(局部感受野),通过在更高层将这些感受不同局部区域的神经元综合起来就可以得到全局图像信息。也就是说,我们可以把一个隐藏层神经元的关注范围减小到只关注图像的其中一个局域范围
权重共享
人眼在观察图像的时候还有一种平移不变形,也就是不管观察对象在空间何处,我们总能通过对象的外表特征模式将其识别出来。也就是说神经元对何种图像模式“敏感”主要是由参数决定的。如果让一张图中的局部连接共享同一套参数(类似滤波器),那么隐藏层神经元就相当于在图像中的各个局部感受野观察同一种特征模式。通过这种参数共享神经网络就拥有了平移不变性,同时参数量进一步大大减少。因为此时参数已经与输入神经元、隐藏神经元数量无关,只与局域感受野(卷积核)设定的大小有关。
进一步,我们可以自然想到,既然每一个神经元的参数都相同,那么我们其实不用“保留”那么多神经元,只保留一个神经元和它的局域感受野参数。让这个神经元走遍图像的每一个角落,这样他就有了一系列输出,输出就组成了卷积运算的特征图。如果我们想提取学习不同的局域特征模式,就可以构建一系列具有不同参数的神经元,彼此走遍图像,得到不同的特征图。
【总结一下,从全连接网络出发,我们原有的隐藏层每一个神经元都连接关注输入图像的每一个点。为了减少参数,也为了让隐藏层的一个神经元只关注一种独特特征模式,就让每一个神经元只连接输入图像的一部分局域感受野,并让它遍历输入图像的每一个角落对不同区域做卷积(输入 × \times ×权重加上激活)操作,这样原来一个神经元的全连接权重矩阵就缩小为一个局域感受野卷积核的权重矩阵,但是这个神经元的一个输出值就拓展成了一个特征图矩阵输出。原来的隐藏层的不同神经元就转换为了不同的卷积核kernel.】
我们有了一层卷积过的特征图之后,可以继续用下一层卷积层对特征图继续进行学习卷积。【比如上一层用不同的卷积核提取嘴巴和鼻子的局域特征后,嘴巴和鼻子的特征就被分到了不同的特征图,特征图组合在一起后,嘴巴和鼻子的特征组合,在下一层会变成新的特征进行学习。】
卷积运算
卷积层是局部连接,卷积核还会考虑通道维度。比如RGB彩色通道图,有三个通道。假设一张图片是 200 × 200 × 3 200\times 200\times 3 200×200×3,一个卷积核是 10 × 10 × 3 10\times 10\times 3 10×10×3, 输出就是一个单通道的特征图 191 × 191 × 1 191\times 191\times 1 191×191×1。也就是说,输入图像中每个 10 × 10 × 3 10\times 10\times 3 10×10×3的区域被卷积后得到一个输出特征值。
卷积运算到底在做什么事情?
简单来说,卷积核做的就是:找到特定像素值的排布分布模式
→
\rightarrow
→与卷积核参数的排布类似
→
\rightarrow
→相乘结果足够去激活激活函数
→
\rightarrow
→模式被提取。我们看下图一个卷积核矩阵的例子。卷积核中参数10排布类似于一条特定曲线:
加入我们把这个卷积核在下图一个老鼠的图像中遍历:
可见,老鼠的屁股这个部分的曲线与卷积核的参数分布非常类似,于是有
也就是说,老鼠屁股这部分区域的像素值与卷积核做卷积操作的时候,会相乘得到一个比较大的乘积。而如果其他某区域的线段与卷积核参数分布相差很大,那么相乘得到的乘积就相对较小。因此老鼠屁股这部分曲线的乘积输入激活函数后会得到一个比较大的输出值。意味着这段特征被这个卷积核提取了出来。当然仅凭这段线段不可能得到“老鼠“的分类预测。但是如果卷积核是一个”眼镜“,那么显然对某些职业的图像分类任务就非常重要了。
池化
特征图后面一半紧跟一个池化层来压缩卷积层输出的信息。
最大池化(max pooling)只保留每个小区域中的最大值。
平均池化是取平均而不是取最大。
【意义:池化操作其实是对特征图的压缩。虽然从分辨率上说,池化(比如最大池化)使得我们丢失了某个特征模式对应的精确位置信息,但是只要池化层大小不是太大,我们还是可以从池化后的特征图中知道大致的方位。而且只要某个特征模式存在,就意味着它可能被卷积核激发挖掘出来,卷积后的值肯定是这块特征图局域中的最大值。也就是说池化后我们还是知道这个特征模式是存在的,我们只需要知道这个模式的有和无问题的与否就行了,因为只要“有”,最后的分类器就能被“告知”如何分类。】
还有一种pooling叫Stochastic pooling(随机池化)
随机池化的计算过程:
- 先将方格中的元素同时除以它们的和sum,得到概率矩阵;
- 按照概率随机选中方格;
- pooling得到的值就是方格位置的值。
使用stochastic pooling时,对矩阵区域求加权平均即可。【在反向传播求导时,只需保留前向传播已经记录被选中节点的位置的值,其它值都为0,这和max-pooling的反向传播非常类似。】
注意:池化不像卷积核一样隐含考虑通道维度。知识把输入特征中每 K × K × 1 K\times K\times 1 K×K×1个区域压缩为1.也就是说池化后的特征图通道数保持不变。
卷积计算公式
假设输入图像是
7
×
7
7\times 7
7×7,卷积核大小是
3
×
3
3\times 3
3×3, 滑动步长是
2
2
2,那么滑动一整行就可以得到3个特征。其中在
7
−
3
=
4
7-3=4
7−3=4的区域中,按照
s
t
r
i
d
e
=
2
stride=2
stride=2可以得到
i
n
p
u
t
s
i
z
e
−
k
e
r
n
e
l
s
i
z
e
s
t
r
i
d
e
=
7
−
3
2
=
2
\dfrac{input\ size-kernel\ size}{stride}=\dfrac{7-3}{2}=2
strideinput size−kernel size=27−3=2.加上第一步的1个卷积核就是2+1=3个特征。因此卷积计算公式是
w
out
=
⌊
w
i
n
+
2
×
pad
−
kernel
Stride
⌋
+
1
w_{\text {out}=}\left\lfloor\frac{w_{i n}+2\times \text{pad}-\text {kernel}}{\text {Stride}}\right\rfloor+1
wout=⌊Stridewin+2×pad−kernel⌋+1
如果输入尺寸不够滑动无法整除,就可以在输入图片的边缘添加0,也就是padding.
很多时候,输入和输出的尺寸要保持一致,
w
o
u
t
=
w
i
n
w_{out}=w_{in}
wout=win, 且
s
t
r
i
d
e
=
1
stride=1
stride=1,那么我们就有
p
a
d
d
i
n
g
=
k
e
r
n
e
l
−
1
2
padding = \frac{kernel-1}{2}
padding=2kernel−1
注意:一般都是向下取整