第一章 神经网络如何工作
文章目录
1.1 尺有所长,尺有所短——关键点
(1)有些任务,对传统的计算机而言很容易,对人类而言却很困难。比如,对数百万个数进行乘法运算。
(2)另一方面,有些任务对传统的计算机而言很难,对人类而言却很简单。比如,从一群人的图片中识别面孔。
1.2 一台简单的预测机——关键点
(1)所有有用的计算机系统都有一个输入和一个输出,并在输入和输出之间进行某种类型的计算。神经网络也是如此。
(2)当我们不能精准的知道一些事情如何运行时,我们可以尝试使用模型来估计其运行方式,在模型中我们可以使用调整的参数。如果我们不知道如何将千米转换为英里,那么我们可以使用线性函数作为模型,并使用可调节的梯度值作为参数。
(3)改进这些模型的一个好方法是,基于模型和已知真实示例之间的比较,得到模型偏移的误差值,调整参数。
1.4 训练简单分类器——关键点
(1)我们使用简单的数学,理解了线形分类器输出误差值和可调节斜率参数之间的关系。也就是说,我们知道了在何种程度上调整斜率,可以消除输出误差值。
(2)使用朴素的调整方法会出现一个问题,即改进后的模型至于最后一次训练样本最匹配,“有效地”忽略了所有以前的训练样本。解决这个问题的一种好方法是使用学习率(learning rate),调节改进速率,这样单一的训练样本就不能主导整个学习过程。
(3)来自真实世界的训练样本可能充满噪声或包含错误。适度更新有助于限制这些错误样本的影响。
1.5 有时候一个分类器不足以求解问题——关键点
多个分类器构建神经网络
(1)如果数据本身不是由单个线性过程支配,那么一个简单的线性分类器不能对数据进行划分,例如:由逻辑XOR运算符支配的数据说明了这一点。
(2)但是解决方案很容易,只需要使用多个线性分类器来划分由单一直线无法分离的数据。
1.6 神经元-大自然的计算机器——关键点
(1)虽然比起现代计算机,生物大脑看起来存储空间少的多,运行速度比较慢,但是生物大脑却可以执行复杂的任务。
(2)相比于传统的计算机系统,生物大脑对损坏和不完善信号具有难以置信的弹性。
(3)由相互连接的神经元组成的生物大脑是人工神经网络的灵感来源。
1.8 凭心而论,矩阵乘法大用用途——关键点
(1)通过神经网络向前馈送信号所需要的大量运算可以表示为矩阵乘法。
(2)不管神经网络的规模如何,将输入输出表达转化为矩阵乘法,使得我们可以更简洁地进行书写。
(3)更重要的是,一些计算机编程语言是理解举证运算的,并认识到潜在计算方法的相似性。这允许计算机高速高效地进行这些运算。
1.12 反向传播误差到更多层中——关键点
(1)神经网络通过调整链接权重进行学习。这种方法由于误差引导,误差就是训练数据所给出正确的答案和实际输出答案之间的差值。
(2)简单说,在输出节点处的误差等于所需值与实际值之间的差值。
(3)然而,与内部节点相关联的误差并不显而易见。一种方法是按照链接权重的比例来分割输出层的误差,然后在每一个内部节点处重组这些误差。
反向传播误差的思想
例1:2个输入节点和两个输出节点之间的简单网络之间的误差反向传播:
由于
e
o
u
t
p
u
t
,
1
e_{output,1}
eoutput,1产生的误差来自于两个绿色箭头
w
1
,
1
和
w
2
,
1
w_{1,1}和w_{2,1}
w1,1和w2,1,所以我们按照不同的权重将产生的误差进行分割给
w
1
,
1
和
w
2
,
1
w_{1,1}和w_{2,1}
w1,1和w2,1,也就是使用误差
e
o
u
t
p
u
t
,
1
e_{output,1}
eoutput,1来调节权重
w
1
,
1
和
w
2
,
1
w_{1,1}和w_{2,1}
w1,1和w2,1,权重的定义如下:
e
o
u
t
p
u
t
,
1
e_{output,1}
eoutput,1对应的
w
1
,
1
w_{1,1}
w1,1:
w
1
,
1
w
1
,
1
+
w
2
,
1
w_{1,1} \over w_{1,1} + w_{2,1}
w1,1+w2,1w1,1
e o u t p u t , 1 e_{output,1} eoutput,1对应的 w 2 , 1 w_{2,1} w2,1: w 2 , 1 w 1 , 1 + w 2 , 1 w_{2,1} \over w_{1,1} + w_{2,1} w1,1+w2,1w2,1
例2:2个输入节点和两个输出节点之间的简单三层网络之间的误差反向传播:
按照例1中计算好
e
o
u
t
p
u
t
,
1
e_{output,1}
eoutput,1和
e
o
u
t
p
u
t
,
2
e_{output,2}
eoutput,2之后可以在他们的基础上计算出
e
h
i
d
d
d
e
n
,
1
e_{hiddden,1}
ehiddden,1和
e
h
i
d
d
d
e
n
,
2
e_{hiddden,2}
ehiddden,2(对应着下图中的e1和e2)。计算公式如下:
e
h
i
d
d
d
e
n
,
1
e_{hiddden,1}
ehiddden,1 = 链接
w
1
,
1
w_{1,1}
w1,1和链接
w
2
,
1
w_{2,1}
w2,1上的分割误差之和 =
e
o
u
t
p
u
t
,
1
e_{output,1}
eoutput,1
w
1
,
1
w
1
,
1
+
w
2
,
1
w_{1,1} \over w_{1,1} + w_{2,1}
w1,1+w2,1w1,1 +
e
o
u
t
p
u
t
,
2
e_{output,2}
eoutput,2
w
1
,
2
w
1
,
2
+
w
2
,
2
w_{1,2} \over w_{1,2} + w_{2,2}
w1,2+w2,2w1,2
ps: 可以观察到需要做的最重要的事情是输出误差与链接权重
w
i
,
j
w_{i,j}
wi,j的乘法。而且较大的权重意味着携带较多的输出误差给隐藏层。此外,上式子的分母是一种归一化因子。
例如下图中紫色部分的和来源于两个橙色箭头所指向求得的结果之和。
误差反向传播到第一层计算原理亦是如此,如下图所示:
1.12 使用矩阵乘法进行反向传播误差——关键点
(1) 反向传播误差可以表示为矩阵乘法。
(2)无论网络规模大小,这使我们能够简洁地表达反向传播误差,同时也允许理解矩阵计算的计算机语言更简练、更快速地完成工作。
(3)这意味着前向馈送信号和反向传播误差都可以使用矩阵计算而变得高效。
ps: 基于上面1.12式,即:式子的分母是一种归一化因子,因此我们忽略这个因子,仅仅失去后反馈误差的大小,我们可以将下面的式1改写成下面的式2:
e
r
r
o
r
h
i
d
d
e
n
=
[
w
1
,
1
w
1
,
1
+
w
2
,
1
w
1
,
2
w
1
,
2
+
w
2
,
2
w
2
,
1
w
2
,
1
+
w
1
,
1
w
2
,
2
w
2
,
2
+
w
1
,
2
]
∗
[
e
1
e
2
]
(式1)
error_{hidden} = \begin{bmatrix} w_{1,1} \over w_{1,1}+ w_{2,1} & w_{1,2} \over w_{1,2} + w_{2,2}\\ w_{2,1} \over w_{2,1}+ w_{1,1} & w_{2,2} \over w_{2,2}+ w_{1,2} \end{bmatrix}*\begin{bmatrix} e1\\e2 \end{bmatrix} \tag{式1}
errorhidden=[w1,1+w2,1w1,1w2,1+w1,1w2,1w1,2+w2,2w1,2w2,2+w1,2w2,2]∗[e1e2](式1)
将
[
w
1
,
1
w
1
,
2
w
2
,
1
w
2
,
2
]
\begin{bmatrix}w_{1,1}&w_{1,2} \\w_{2,1}&w_{2,2}\end{bmatrix}
[w1,1w2,1w1,2w2,2]记作为
W
T
W^T
WT,因此我们可以使用矩阵的方法来向后传播误差,即式子:
e
r
r
o
r
h
i
d
d
e
n
error_{hidden}
errorhidden =
W
T
∗
e
r
r
o
r
o
u
t
p
u
t
W^T*error_{output}
WT∗erroroutput
ps: 实践证明将归一化因子切除,这种相对简单的误差信号反馈方式,与我们之前相对复杂的方式一样有效。
1.14 我们实际上如何更新权重——关键点
(1)梯度下降法是求解函数最小值的一种很好的方法,当函数非常复杂困难,并且不能轻易使用数学代数求解函数时,这种方法却发挥了很好的作用。
(2)更重要的是,当函数有很多参数,一些其它方法不切实际,或者会得出错误答案,这种方法仍然可以适用。
(3)这种方法也具有弹性,可以容忍不完善的数据,如果我们不完美地描述函数,或我们偶尔意外地走错了一步,也不会错的离谱。
(4)神经网络的误差是内部链接权重的函数。
(5)改进神经网络,意味着通过改变权重减少这种误差。
(6)直接选择合适的权重太难了。另一种方法是,通过误差函数的梯度下降,采取小步长,迭代地改进权重。所迈出的每一步的方向都是在当前位置向下斜率最大的方向,这就是所谓的梯度下降。
(7)使用微积分可以很容易的计算出误差斜率。
将误差函数当作复杂的函数(在山顶需要下到山谷的例子),在选择误差函数的时候应该选择哪一个呢?三个候选项分别是(目标值-实际值)、|目标值-实际值|、 ( 目标值 − 实际值 ) 2 (目标值-实际值)^2 (目标值−实际值)2。
一般选择第三种因的原因:
(1)选择差的平方,即 ( 目标值 − 实际值 ) 2 (目标值-实际值)^2 (目标值−实际值)2。使用误差的平方,我们可以很容易使用代数计算出梯度下降的斜率。
(2)误差函数平滑连续的性质好,会使得梯度下降法很好地发挥作用——没有间断,也没有突然的跳跃。
(3)越接近最小值,梯度越小,这意味着,如果我们是用这个函数调节布长,超调的风险就会变得很小。
为了避免终止于错误的山谷或者错误的函数最小值,我们从山上的不同点开始,多次训练神经网络,确保并不总是终止于错误的山谷。不同的起点意味着选择不同的参数,在神经网络的情况下,这意味着选择不同的起始链接权重。
首先展开误差,这是对目标值和实际值之差的平方进行求和,这是针对所有n个输出节点的和:
∂
E
∂
W
j
,
k
=
∂
∂
W
j
,
k
∑
n
(
t
n
−
o
n
)
2
\frac{\partial E}{\partial W_{j,k}} = \frac{\partial}{\partial W_{j,k}} {\textstyle \sum_{n}(t_{n}-o_{n})^2}
∂Wj,k∂E=∂Wj,k∂∑n(tn−on)2
因为节点的输出只取决于所连接的链接,就是取决于链接权重,所以我们将上面的式子写为:
∂
E
∂
W
j
,
k
=
∂
∂
W
j
,
k
(
t
n
−
o
n
)
2
\frac{\partial E}{\partial W_{j,k}} = \frac{\partial}{\partial W_{j,k}} {\textstyle(t_{n}-o_{n})^2}
∂Wj,k∂E=∂Wj,k∂(tn−on)2
再利用链式法则:
∂
E
∂
W
j
,
k
=
∂
E
∂
o
k
∗
∂
o
k
∂
W
j
,
k
\frac{\partial E}{\partial W_{j,k}} = \frac{\partial E}{\partial o_{k}} *\frac{\partial o_{k}}{\partial W_{j,k}}
∂Wj,k∂E=∂ok∂E∗∂Wj,k∂ok
接下来对每个简单的部分各个击破得到:
∂
E
∂
W
j
,
k
=
−
2
(
t
k
−
o
k
)
∗
∂
o
k
∂
W
j
,
k
(式2)
\frac{\partial E}{\partial W_{j,k}} = -2(t_{k}-o_{k}) *\frac{\partial o_{k}}{\partial W_{j,k}} \tag {式2}
∂Wj,k∂E=−2(tk−ok)∗∂Wj,k∂ok(式2)
对于第二项,我们需要仔细考虑一下:
o
k
o_k
ok是节点k的输出,是在连接输入信号上进行加权求和,在所得到的的结果上应用S函数得到的结果,即:
∂
E
∂
W
j
,
k
=
−
2
(
t
k
−
o
k
)
∗
∂
∂
W
j
,
k
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
(式3)
\frac{\partial E}{\partial W_{j,k}} = -2(t_{k}-o_{k}) *\frac{\partial }{\partial W_{j,k}} sigmoid(∑_jW_{j,k}*o_j) \tag {式3}
∂Wj,k∂E=−2(tk−ok)∗∂Wj,k∂sigmoid(j∑Wj,k∗oj)(式3)
其中
o
j
o_{j}
oj是前一个隐藏层节点的输出,而不是最终层的输出
o
k
o_{k}
ok
接下来在解决微分函数S:对S函数求微分公式:
∂
∂
x
s
i
g
m
o
i
d
(
x
)
=
s
i
g
m
o
i
d
(
x
)
∗
(
1
−
s
i
g
m
o
i
d
(
x
)
)
(式4)
\frac{\partial }{\partial x}sigmoid(x) =sigmoid(x)*(1-sigmoid(x)) \tag {式4}
∂x∂sigmoid(x)=sigmoid(x)∗(1−sigmoid(x))(式4)
将上面的式4应用到式3可以得到:
∂
E
∂
W
j
,
k
=
−
2
(
t
k
−
o
k
)
∗
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
∗
(
1
−
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
)
∗
∂
∂
W
j
,
k
(
∑
j
W
j
,
k
∗
o
j
)
\frac{\partial E}{\partial W_{j,k}} = -2(t_{k}-o_{k}) * sigmoid(∑_jW_{j,k}*o_j)*(1-sigmoid(∑_jW_{j,k}*o_j)) *\frac{\partial }{\partial W_{j,k}}(∑_jW_{j,k}*o_j)
∂Wj,k∂E=−2(tk−ok)∗sigmoid(j∑Wj,k∗oj)∗(1−sigmoid(j∑Wj,k∗oj))∗∂Wj,k∂(j∑Wj,k∗oj)
=
−
2
(
t
k
−
o
k
)
∗
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
∗
(
1
−
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
)
∗
o
j
(式5)
= -2(t_{k}-o_{k}) * sigmoid(∑_jW_{j,k}*o_j)*(1-sigmoid(∑_jW_{j,k}*o_j)) *o_j \tag {式5}
=−2(tk−ok)∗sigmoid(j∑Wj,k∗oj)∗(1−sigmoid(j∑Wj,k∗oj))∗oj(式5)
其中
∂
∂
W
j
,
k
(
∑
j
W
j
,
k
∗
o
j
)
\frac{\partial }{\partial W_{j,k}}(∑_jW_{j,k}*o_j)
∂Wj,k∂(∑jWj,k∗oj),是因为在sigmoid()函数内部的表达式也需要对
W
j
,
k
W_{j,k}
Wj,k进行微分,因此对S函数微分项再次应用链式法则,就得到了
o
j
o_{j}
oj。
又因为我们只对误差函数的斜率方向感兴趣,这样我们可以使用梯度下降的方法,因此可以去掉前面的常树2。即:
∂
E
∂
W
j
,
k
=
−
(
t
k
−
o
k
)
∗
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
∗
(
1
−
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
)
∗
o
j
(式6)
\frac{\partial E}{\partial W_{j,k}} = -(t_{k}-o_{k}) * sigmoid(∑_jW_{j,k}*o_j)*(1-sigmoid(∑_jW_{j,k}*o_j)) *o_j \tag {式6}
∂Wj,k∂E=−(tk−ok)∗sigmoid(j∑Wj,k∗oj)∗(1−sigmoid(j∑Wj,k∗oj))∗oj(式6)
其中式6中的
(
t
k
−
o
k
)
(t_{k}-o_{k})
(tk−ok)=(目标值-实际值)也就是误差
e
e
e,因此我们可以得到最终的误差函数斜率,用来调整输入层和隐藏层之间的权重,当然同样也适用于隐藏层和输出层之间权重的调节。
∂
E
∂
W
j
,
k
=
−
(
e
j
)
∗
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
∗
(
1
−
s
i
g
m
o
i
d
(
∑
j
W
j
,
k
∗
o
j
)
)
∗
o
j
(式7)
\frac{\partial E}{\partial W_{j,k}} = -(e_{j}) * sigmoid(∑_jW_{j,k}*o_j)*(1-sigmoid(∑_jW_{j,k}*o_j)) *o_j \tag {式7}
∂Wj,k∂E=−(ej)∗sigmoid(j∑Wj,k∗oj)∗(1−sigmoid(j∑Wj,k∗oj))∗oj(式7)
将上式应用到每一层训练样本后,更新权重,请自记住权重改变的方向与梯度方向是相反的。我们使用学习因子,调节变化,我们可以根据特定的问题,调节这个学习因子。当我们建立线性分类器,作为避免被错误的训练样本拉的太远的一种方式,同事也为了保证权重不会由于持续的超调而在最小值附近来回摆动,即学习因子用数学形式来表达:
n
e
w
W
j
,
k
=
o
l
d
W
j
,
k
−
α
∗
∂
E
∂
W
j
,
k
new W_{j,k} = old W_{j,k} - α*\frac{\partial E}{\partial W_{j,k}}
newWj,k=oldWj,k−α∗∂Wj,k∂E
更新后的权重
W
J
,
K
W_{J,K}
WJ,K是由于刚刚到的误差斜率取反来调整旧的权重而得到,如果斜率是正的,我们希望减小权重,如果斜率是负的就是增加权重,没有使用“-”号,其中α是我们常说的学习率。
△
w
j
,
k
=
α
∗
E
k
∗
O
k
(
1
−
O
k
)
∗
O
j
T
△w_{j,k} = α*E_{k}*O_k(1-O_k)*O_{j}^T
△wj,k=α∗Ek∗Ok(1−Ok)∗OjT
1.16 准备数据——关键点
(1) 如果输入、输出、初始权重数据的准备与网络设计和实际求解的问题不匹配,那么神经网络并不能很好地工作。
(2)一个常见的问题是饱和。在这个时候,大信号(这有时候是由大权重带来的)导致应用在信号上的激活函数的斜率变得非常平缓。这降低了神经网络学习到更好权重的能力。
(3)另一个问题是零值信号或者零值权重。这也可以使得网络丧失学习更好权重的能力。
(4)内部链接的权重应该是随机分配的,值比较小,但要避免零值。如果节点的传入链接较多,有些人会使用相对复杂的规则,如减少这些权重的大小。
(5)输入调整到较小值,但不能为零,一个常见的范围是0.01~0.99或者-1.0~1.0,使用这个范围,取决于是否匹配了问题。
(6)输出应该在激活函数能够生成的值的范围内。逻辑S函数是不可能生成小于等于0或大于等于1的值。将训练目标设置在有效的范围之外,将会驱使产生越来越大的权重,导致网络饱和,一个合适的范围为0.01~0.99。