文章目录
0 概述
第4周我们引入了神经网络,并给出了神经网络前向传播的计算方法。也就是完成了假设模型的
h
θ
(
x
)
h_\theta(x)
hθ(x) 的定义,那么下一步就是对损失函数和优化方法的探究。
本周,将要学习的反向传播算法,是神经网络独有的优化方法,在神经网络中占有至关重要的左右。
1. 课程大纲
2. 课程内容
由于神经网络很复杂,在开始课程内容之前,我们先对神经网络参数符号进行约定如下:
训练集中有
m
m
m个训练样本
{
(
x
(
1
)
,
y
(
1
)
)
,
(
x
(
2
)
,
y
(
2
)
)
,
⋯
 
,
(
x
(
m
)
,
y
(
m
)
)
}
\left\{\left(x^{(1)}, y^{(1)}\right),\left(x^{(2)}, y^{(2)}\right), \cdots,\left(x^{(m)}, y^{(m)}\right)\right\}
{(x(1),y(1)),(x(2),y(2)),⋯,(x(m),y(m))};
注意:神经元的每个节点,都是数值标量,这是神经网络的简化之处(个人观点)
z
i
j
(
j
)
z_{i j}^{(j)}
zij(j):第
j
j
j 层的第
i
i
i 个节点(神经元)的“计算值”
a
i
(
j
)
a_{i}^{(j)}
ai(j):第
j
j
j 层的第
i
i
i 个节点(神经元)的“激活值”
Θ
i
,
j
(
l
)
\Theta_{i, j}^{(l)}
Θi,j(l):映射第
l
l
l 层到第
l
+
1
l+1
l+1 层的权值矩阵的第
i
i
i 行第
j
j
j 列的分量
L
L
L:神经网络总层数(包括输入层、隐层和输出层)
S
l
S_{l}
Sl:第
L
L
L层的神经元数量(不包括手动加入的偏置
a
0
(
l
)
a_{0}^{(l)}
a0(l));
K
K
K:输出层的神经元数目;
h
θ
(
x
)
k
h_{\theta}(x)_{k}
hθ(x)k:第
k
k
k 个预测输出结果
x
(
i
)
x^{(i)}
x(i):第
i
i
i 个样本特征向量
x
k
(
i
)
x_{k}^{(i)}
xk(i):第
i
i
i 个样本的第
k
k
k 个特征值
y
(
i
)
y^{(i)}
y(i):第
i
i
i 个样本实际结果向量
y
k
(
i
)
y_{k}^{(i)}
yk(i):第
i
i
i 个样本结果向量的第
k
k
k 个分量
2.1 神经网络损失函数的定义
上周研究的是逻辑回归单元组成的神经网络,因此损失函数也沿袭logistic Regression进行定义。
逻辑回归的损失函数如下:
costFunction
=
F
(
θ
)
=
−
1
m
[
∑
i
=
1
m
y
(
i
)
log
h
θ
(
x
(
i
)
)
+
(
1
−
y
(
i
)
)
log
(
1
−
h
θ
(
x
(
i
)
)
)
]
+
λ
2
m
∑
j
=
1
n
θ
j
2
=\mathrm{F}(\theta)=-\frac{1}{m}\left[\sum_{i=1}^{m} y^{(i)} \log h_{\theta}\left(x^{(i)}\right)+\left(1-y^{(i)}\right) \log \left(1-h_{\theta}\left(x^{(i)}\right)\right)\right]+\frac{\lambda}{2 m} \sum_{j=1}^{n} \theta_{j}^{2}
=F(θ)=−m1[∑i=1my(i)loghθ(x(i))+(1−y(i))log(1−hθ(x(i)))]+2mλ∑j=1nθj2
因此,神经网络的损失函数为:
J
(
Θ
)
=
−
1
m
[
∑
i
=
1
m
∑
k
=
1
K
y
k
(
i
)
log
(
h
Θ
(
x
(
i
)
)
)
k
+
(
1
−
y
k
(
i
)
)
log
(
1
−
(
h
Θ
(
x
(
i
)
)
)
k
)
]
+
λ
2
m
∑
l
=
1
L
−
1
∑
i
=
1
s
l
∑
j
=
1
s
l
+
1
(
Θ
j
i
(
l
)
)
2
\begin{aligned} J(\Theta)=&-\frac{1}{m}\left[\sum_{i=1}^{m} \sum_{k=1}^{K} y_{k}^{(i)} \log \left(h_{\Theta}\left(x^{(i)}\right)\right)_{k}+\left(1-y_{k}^{(i)}\right) \log \left(1-\left(h_{\Theta}\left(x^{(i)}\right)\right)_{k}\right)\right] \\ &+\frac{\lambda}{2 m} \sum_{l=1}^{L-1} \sum_{i=1}^{s_{l}} \sum_{j=1}^{s_{l+1}}\left(\Theta_{j i}^{(l)}\right)^{2} \end{aligned}
J(Θ)=−m1[i=1∑mk=1∑Kyk(i)log(hΘ(x(i)))k+(1−yk(i))log(1−(hΘ(x(i)))k)]+2mλl=1∑L−1i=1∑slj=1∑sl+1(Θji(l))2
h
Θ
(
x
)
h_{\Theta}(x)
hΘ(x) 是一个 K 维向量,对应了训练集每个样本的输出向量
y
(
i
)
y^{(i)}
y(i);
i
i
i表示第
i
i
i个训练样本,总共有
m
m
m个;
正则项看起来很复杂,其实就是对系数矩阵
Θ
\Theta
Θ的每一个元素进行正则化(没有偏置项系数);
2.2 反向传播算法
与梯度下降一样,反向传播算法最终也是要求损失函数对 Θ \Theta Θ的偏导项,然后用偏导项对 Θ \Theta Θ进行迭代更新。
2.2.1 计算偏导项的公式
吴恩达并没有给出链式求导的方法,而是提供了一个结论,然后基于这个结论进行后续的求解过程。
∂
∂
θ
i
,
j
(
l
)
F
(
Θ
)
=
D
i
,
j
(
l
)
:
=
{
1
m
(
Δ
i
,
j
(
l
)
+
λ
Θ
i
,
j
(
l
)
)
j
≠
0
1
m
Δ
i
,
j
(
l
)
j
=
0
\frac{\partial}{\partial \theta_{i, j}^{(l)}} F(\Theta)=D_{i, j}^{(l)} :=\left\{\begin{array}{ll}{\frac{1}{m}\left(\Delta_{i, j}^{(l)}+\lambda \Theta_{i, j}^{(l)}\right)} & {j \neq 0} \\ {\frac{1}{m} \Delta_{i, j}^{(l)}} & {j=0}\end{array}\right.
∂θi,j(l)∂F(Θ)=Di,j(l):={m1(Δi,j(l)+λΘi,j(l))m1Δi,j(l)j̸=0j=0
其中,
Δ
i
,
j
(
l
)
:
=
Δ
i
,
j
(
l
)
+
a
j
(
l
)
δ
i
(
l
+
1
)
\Delta_{i, j}^{(l)} :=\Delta_{i, j}^{(l)}+a_{j}^{(l)} \delta_{i}^{(l+1)}
Δi,j(l):=Δi,j(l)+aj(l)δi(l+1)
δ j ( L ) = a j ( L ) − y j = ( h θ ( x ) ) j − y j \begin{aligned} \delta_{j}^{(L)} &=a_{j}^{(L)}-y_{j}=\left(h_{\theta}(x)\right)_{j}-y_{j} \end{aligned} δj(L)=aj(L)−yj=(hθ(x))j−yj
δ ( l − 1 ) = ( Θ ( l − 1 ) ) T δ ( l ) ⋅ ∗ g ′ ( z ( l ) ) \delta^{(l-1)}=\left(\Theta^{(l-1)}\right)^{T} \delta^{(l)} \cdot^{*} g^{\prime}\left(z^{(l)}\right) δ(l−1)=(Θ(l−1))Tδ(l)⋅∗g′(z(l))
g
′
(
z
(
l
)
)
=
a
(
l
)
⋅
∗
(
1
−
a
(
l
)
)
g^{\prime}\left(z^{(l)}\right)=a^{(l)} \cdot^{*}\left(1-a^{(l)}\right)
g′(z(l))=a(l)⋅∗(1−a(l))
注意:
δ
(
1
)
\delta^{(1)}
δ(1)不用求解,因为输入和实际的没有偏差。
2.2.2 求解过程
有一个训练集
{
(
x
(
1
)
,
y
(
1
)
)
,
(
x
(
2
)
,
y
(
2
)
)
,
⋯
 
,
(
x
(
m
)
,
y
(
m
)
)
}
\begin{Bmatrix} (x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}), \cdots ,(x^{(m)},y^{(m)}) \end{Bmatrix}
{(x(1),y(1)),(x(2),y(2)),⋯,(x(m),y(m))},初始化每一个
Δ
i
,
j
(
l
)
:
=
0
\Delta^{(l)}_{i,j} := 0
Δi,j(l):=0 ,即初始矩阵是全零矩阵。
针对
1
−
m
1-m
1−m 训练集开始以下步骤的训练:
STEP 1 :前向传播
设
a
(
1
)
=
x
a^{(1)}=x
a(1)=x,按照前向传播计算每一层的$a^{(l)}。
STEP 2 :计算误差
利用
y
(
t
)
y^{(t)}
y(t),计算
δ
(
L
)
=
a
(
L
)
−
y
t
\delta^{(L)}=a^{(L)}-y^{t}
δ(L)=a(L)−yt。
其中
L
L
L 是我们的总层数,
a
(
L
)
a^{(L)}
a(L) 是最后一层激活单元输出的向量。所以我们最后一层的“误差值”仅仅是我们在最后一层的实际结果和 y 中的正确输出的差异。
STEP 3 : 反向传播
计算
δ
(
L
−
1
)
,
δ
(
L
−
2
)
,
⋯
 
,
δ
(
2
)
\delta^{(L-1)},\delta^{(L-2)},\cdots,\delta^{(2)}
δ(L−1),δ(L−2),⋯,δ(2) ,得出每一层神经节点的误差,
δ ( l ) = ( ( Θ ( l ) ) ( T ) δ ( l + 1 ) ) . ∗ a ( l ) . ∗ ( 1 − a ( l ) ) \delta^{(l)} = ((\Theta^{(l)})^{(T)}\delta^{(l+1)}).* a^{(l)} .*(1-a^{(l)}) δ(l)=((Θ(l))(T)δ(l+1)).∗a(l).∗(1−a(l))
STEP 4:计算偏导数
最后利用
Δ
i
,
j
(
l
)
:
=
Δ
i
,
j
(
l
)
+
a
j
(
l
)
δ
i
(
l
+
1
)
\Delta^{(l)}_{i,j} := \Delta^{(l)}_{i,j} + a_{j}^{(l)}\delta_{i}^{(l+1)}
Δi,j(l):=Δi,j(l)+aj(l)δi(l+1),或者矢量表示为
Δ
(
l
)
:
=
Δ
(
l
)
+
δ
(
l
+
1
)
(
a
(
l
)
)
T
\Delta^{(l)} := \Delta^{(l)} + \delta^{(l+1)}(a^{(l)})^{T}
Δ(l):=Δ(l)+δ(l+1)(a(l))T。
∂ ∂ θ i , j ( l ) F ( Θ ) = D i , j ( l ) : = { 1 m ( Δ i , j ( l ) + λ Θ i , j ( l ) ) j ≠ 0 1 m Δ i , j ( l ) j = 0 \frac{\partial}{\partial \theta_{i, j}^{(l)}} F(\Theta)=D_{i, j}^{(l)} :=\left\{\begin{array}{ll}{\frac{1}{m}\left(\Delta_{i, j}^{(l)}+\lambda \Theta_{i, j}^{(l)}\right)} & {j \neq 0} \\ {\frac{1}{m} \Delta_{i, j}^{(l)}} & {j=0}\end{array}\right. ∂θi,j(l)∂F(Θ)=Di,j(l):={m1(Δi,j(l)+λΘi,j(l))m1Δi,j(l)j̸=0j=0
STEP 5:更新
Θ
\Theta
Θ
Θ
(
l
)
=
Θ
(
l
)
−
α
D
(
l
)
\Theta^{(l)}=\Theta^{(l)}-\alpha D^{(l)}
Θ(l)=Θ(l)−αD(l)
其中,
α
\alpha
α为学习率。
以上流程不免产生两个问题:
(1) 为什么通过这种方式求解偏导数,原理是什么?
(2) 继续迭代,
Δ
i
,
j
(
l
)
\Delta^{(l)}_{i,j}
Δi,j(l)是否每次迭代都初始化全0矩阵?
针对以上两个问题,需要进行数学推导,后续将专门写一篇文章讲解。
2.3 编程算法实现
2.3.1 参数展开
将参数矩阵展开成一个
n
∗
1
n*1
n∗1的向量,方便参数的传递。
具体操作,
假如
Θ
1
,
Θ
2
,
Θ
3
\Theta_1,\Theta_2,\Theta_3
Θ1,Θ2,Θ3 参数和
D
(
1
)
,
D
(
2
)
,
D
(
3
)
D^{(1)},D^{(2)},D^{(3)}
D(1),D(2),D(3) 参数,
Θ
1
\Theta1
Θ1 是
10
∗
11
10 * 11
10∗11维,
Θ
2
\Theta2
Θ2 是
10
∗
11
10 * 11
10∗11维,
Θ
3
\Theta3
Θ3 是
1
∗
11
1 * 11
1∗11维。
% 打包成一个向量
thetaVector = [ Theta1(:); Theta2(:); Theta3(:); ]
deltaVector = [ D1(:); D2(:); D3(:) ]
% 解包还原
Theta1 = reshape(thetaVector(1:110),10,11)
Theta2 = reshape(thetaVector(111:220),10,11)
Theta3 = reshape(thetaVector(221:231),1,11)
其中,
reshape是一个将向量元素去除,并重新组成矩阵的函数。详见octave
为什么要进行参数展开?
为了利用梯度下降的优化算法,需要用到 fminunc 函数。其输入的参数是
θ
\theta
θ 必须是向量,函数的返回值是代价函数 jVal 和导数值 gradient。
使用fminunc的步骤如下:
step 1:先将
Θ
1
,
Θ
2
,
Θ
3
\Theta_1,\Theta_2,\Theta_3
Θ1,Θ2,Θ3 ,这些矩阵展开为一个长向量赋值给 initialTheta,然后作为theta参数的初始设置传入优化函数 fminunc。
step 2:再实现代价函数 costFunction。costFunction 函数将传入参数 thetaVec(就是刚才包含所有
Θ
\Theta
Θ 参数的向量),然后通过 reshape 函数得到初始的矩阵,这样可以更方便地通过前向传播和反向传播以求得导数
D
(
1
)
,
D
(
2
)
,
D
(
3
)
D^{(1)},D^{(2)},D^{(3)}
D(1),D(2),D(3) 和代价函数
F
(
Θ
)
F(\Theta)
F(Θ) 。
step 3:最后按顺序展开得到 gradientVec,让它们保持和之前展开的
θ
\theta
θ 值同样的顺序。以一个向量的形式返回这些导数值。
2.3.2 梯度检验
理论上,在我们使用梯度下降的时候,
F
(
Θ
)
F(\Theta)
F(Θ) 每次都会下降。但是由于反向传播的复杂性,可能导致计算过程存在bug,因此需要进行梯度检验,以减少错误的概率。
使用双侧差分算法,近似求解偏导数:
∂ ∂ θ 1 J ( θ ) ≈ J ( θ 1 + ϵ , θ 2 , θ 3 , … , θ n ) − J ( θ 1 − ϵ , θ 2 , θ 3 , … , θ n ) 2 ϵ ∂ ∂ θ 2 J ( θ ) ≈ J ( θ 1 , θ 2 + ϵ , θ 3 , … , θ n ) − J ( θ 1 , θ 2 − ϵ , θ 3 , … , θ n ) 2 ϵ ∂ ∂ θ n J ( θ ) ≈ J ( θ 1 , θ 2 , θ 3 , … , θ n + ϵ ) − J ( θ 1 , θ 2 , θ 3 , … , θ n − ϵ ) 2 ϵ \begin{aligned} \frac{\partial}{\partial \theta_{1}} J(\theta) & \approx \frac{J\left(\theta_{1}+\epsilon, \theta_{2}, \theta_{3}, \ldots, \theta_{n}\right)-J\left(\theta_{1}-\epsilon, \theta_{2}, \theta_{3}, \ldots, \theta_{n}\right)}{2 \epsilon} \\ \frac{\partial}{\partial \theta_{2}} J(\theta) & \approx \frac{J\left(\theta_{1}, \theta_{2}+\epsilon, \theta_{3}, \ldots, \theta_{n}\right)-J\left(\theta_{1}, \theta_{2}-\epsilon, \theta_{3}, \ldots, \theta_{n}\right)}{2 \epsilon} \\ \frac{\partial}{\partial \theta_{n}} J(\theta) & \approx \frac{J\left(\theta_{1}, \theta_{2}, \theta_{3}, \ldots, \theta_{n}+\epsilon\right)-J\left(\theta_{1}, \theta_{2}, \theta_{3}, \ldots, \theta_{n}-\epsilon\right)}{2 \epsilon} \end{aligned} ∂θ1∂J(θ)∂θ2∂J(θ)∂θn∂J(θ)≈2ϵJ(θ1+ϵ,θ2,θ3,…,θn)−J(θ1−ϵ,θ2,θ3,…,θn)≈2ϵJ(θ1,θ2+ϵ,θ3,…,θn)−J(θ1,θ2−ϵ,θ3,…,θn)≈2ϵJ(θ1,θ2,θ3,…,θn+ϵ)−J(θ1,θ2,θ3,…,θn−ϵ)
注:为什么没有使用单侧差分? 因为单侧差分计算出来的是左导数或者右导数,有可能不准确。
检查反向传播计算出来的导数 DVec 约等于上面计算出来的近似偏导,则代表反向传播的实现是正确的。
总结一下:
- 通过反向传播来计算偏导数DVec
- 使用双侧差分计算近似偏导
- 比较Dvec是否约等于近似偏导
- 使用算法学习的时候记得要关闭这个梯度检验,梯度检验只在代码测试阶段进行。
2.3.3 随机初始化
在进行反向传播之前,需要对
Θ
\Theta
Θ进行初始化,求解前向传导。
为什么不能简单的将
Θ
\Theta
Θ初始化为全0矩阵?
如图所示,如果初始化位全0矩阵,则进行反向传播计算偏导时,对于所有
Θ
i
j
(
l
)
\Theta_{i j}^{(l)}
Θij(l)的偏导是一样的。这就导致了在参数更新的情况下,两个参数是一样的。无论怎么重复计算其两边的激励还是一样的。
上述问题被称为对称权重问题,也就是所有权重都是一样的。所以随机初始化是解决这个问题的方法。
随机初始化,将初始化权值 Θ i j ( l ) \Theta_{ij}^{(l)} Θij(l) 的范围限定在 [ − Φ , Φ ] [-\Phi ,\Phi ] [−Φ,Φ] ,产生随机数,初始化权值矩阵。
%If the dimensions of Theta1 is 10x11, Theta2 is 10x11 and Theta3 is 1x11.
Theta1 = rand(10,11) * (2 * INIT_PHI) - INIT_PHI;
Theta2 = rand(10,11) * (2 * INIT_PHI) - INIT_PHI;
Theta3 = rand(1,11) * (2 * INIT_PHI) - INIT_PHI;
2.4 神经网络使用步骤总结
STEP 1:设计神经网络
- 输入单元个数,是输入变量的 x ( i ) x^{(i)} x(i)的维度。
- 输出单元是分类的个数,比如有三类,则可能值 y = [ 1 0 0 ] y=\left[ \begin{array}{l}{1} \\ {0} \\ {0}\end{array}\right] y=⎣⎡100⎦⎤ or [ 0 1 0 ] \left[ \begin{array}{c}{0} \\ {1} \\ {0}\end{array}\right] ⎣⎡010⎦⎤ or [ 0 0 1 ] \left[ \begin{array}{c}{0} \\ {0} \\ {1}\end{array}\right] ⎣⎡001⎦⎤
- 隐层的单元数,理论上越多越好,但是考虑计算成本均衡问题。
- 默认1个隐层,如果有多隐层,则建议每个隐层单元数相同
STEP 2 :训练神经网络
- 随机初始化权重。初始化的值是随机的,值很小,接近于零。
- 执行前向传播算法,对于每一个 x ( i ) x^{(i)} x(i) 计算出假设函数 h Θ ( x ( i ) ) h_\Theta(x^{(i)}) hΘ(x(i)) 。
- 计算出代价函数 F ( Θ ) F(\Theta) F(Θ) 。
- 执行反向传播算法,计算出偏导数
∂
∂
Θ
j
k
(
l
)
F
(
Θ
)
\frac{\partial}{\partial\Theta_{jk}^{(l)}}F(\Theta)
∂Θjk(l)∂F(Θ) 。
具体求解步骤,参考2.2.2 反向传播求解过程一节 - 利用梯度检查,对比反向传播算法计算得到的偏导数项是否与梯度检验算法计算出的导数项基本相等。
- 后我们利用梯度下降算法或者更高级的算法例如 LBFGS、共轭梯度法等,结合之前算出的偏导数项,最小化代价函数 F ( Θ ) F(\Theta) F(Θ) 算出权值的大小 Θ \Theta Θ 。
理想状态下 ,满足 h Θ ( x ( i ) ) ≈ y ( i ) h_{\Theta}\left(x^{(i)}\right) \approx y^{(i)} hΘ(x(i))≈y(i),就认为代价函数最小了,由于代价函数 F ( Θ ) F(\Theta) F(Θ) 是非凸的,因此我们最终可以用局部最小值代替全局最小值。
3. 课后编程作业
我将课后编程作业的参考答案上传到了github上,包括了octave版本和python版本,大家可参考使用。
https://github.com/GH-SUSAN/Machine-Learning-MarkDown/tree/master/week5
4. 总结
本周学习了反向传播算法,这是神经网络训练目前最常用也最好用的方法,学习深刻理解和体会。
这里留下了一个尾巴,就是为什么吴恩达没有用链式求导计算偏导数,而是采用以上误差传导方式,计算偏导,原理在哪里?我后边需要继续总结这个问题。
学习了反向传播之后,对神经网络的整个应用和计算就闭环了,这是神经网络的起步,也是最重要的基石。未来深度学习,无非就是在此基础之上的组合和扩展。