Unrolling Parameters
对于神经网络的操作,一般都是基于矩阵的:
θ
(
1
)
,
θ
(
2
)
,
θ
(
3
)
,
D
(
1
)
,
D
(
2
)
,
D
(
3
)
,
\theta^{(1)},\theta^{(2)},\theta^{(3)},\\ D^{(1)},D^{(2)},D^{(3)},
θ(1),θ(2),θ(3),D(1),D(2),D(3),
为了能够使用优化方程,如"fminunc()",我们需要将上述矩阵平铺放入到一个向量当中:
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)
Gradient Checking
由于反向传播算法相对来说比较复杂,所以在实际应用当中经常会出现很多小bug,而且很多时候算法是可以运行的,并且一开始运行确实代价函数是在下降了,但其实算法是存在一些问题的。又因为机器学习算法运行时间往往是很长的,我们不能总是等到算法结束,出现错误结果再来调bug,这样会浪费我们非常非常多的时间。
为了规避这种问题,我们需要引入gradient checking环节。gradient checking的核心思想是:
∂
J
(
θ
)
∂
θ
≈
J
(
θ
+
ϵ
)
−
J
(
θ
−
ϵ
)
2
ϵ
\frac{\partial J(\theta)}{\partial \theta}\approx \frac {J(\theta + \epsilon)-J(\theta - \epsilon)}{2\epsilon}
∂θ∂J(θ)≈2ϵJ(θ+ϵ)−J(θ−ϵ)
由于我们的参数是多维的,所以实际上梯度验证应该是:
一般
ϵ
=
1
0
−
4
\epsilon=10^{-4}
ϵ=10−4 就可以保证正常运行了,如果
ϵ
\epsilon
ϵ取得太小会导致数值问题。
epsilon = 1e-4;
for i = 1:n,
thetaPlus = theta;
thetaPlus(i) += epsilon;
thetaMinus = theta;
thetaMinus(i) -= epsilon;
gradApprox(i) = (J(thetaPlus) - J(thetaMinus))/(2*epsilon)
end;
Gradient Checking只需要运行迭代一次,然后完成验证之后,就要将gradient checking停掉,然后运行反向传播算法即可。如果不停掉,每次迭代都进行验证,将浪费太多时间。
Random Initialization
对于神经网络来说,参数全零初始化是不行的,全零初始化,会导致所有的隐藏层的神经元的输出都相同,无法学习多个feature,相当于只有一个神经元。其根本原因是因为每层的每组参数初始为同一个值(这个每层每组的概念参考下图),这样导致前向传递时,隐藏层神经元的输出相同,然后后向传递时隐藏层神经元残差也相同,那么这就导致每组参数的更新都是一样的,然后隐藏层输出依旧相同。如下图:
所以我们需要进行随机初始化:
Theta1 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta2 = rand(10,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
Theta3 = rand(1,11) * (2 * INIT_EPSILON) - INIT_EPSILON;
一个有效的选择
ϵ
\epsilon
ϵ 的策略是:
ϵ
i
n
i
t
=
6
s
l
+
s
l
+
1
\epsilon_{init} = \frac{\sqrt{6}}{\sqrt{s_l+s_{l+1}}}
ϵinit=sl+sl+16
Putting It Together
最后呢,我们来完整的走一遍神经网络的流程:
- 确定神经网络的布局,输入层的单元数,输出层的单元数,隐藏层的层数以及每个隐藏层的单元数
- 随机初始化权重 θ \theta θ
- 执行前向传播算法算出所有的 h θ ( x ( i ) ) h_\theta(x^{(i)}) hθ(x(i))
- 计算代价函数的值
- 执行后向传播算法计算偏导数
- 运用gradient checking验证反向传播算法是否成功运行,如果是,不再验证
- 运用梯度下降或者内置的优化方程来最小化代价函数,求得
θ
\theta
θ
最后申明一定,神经网络的代价函数并非凸函数,所以最终我们会停滞在局部最优解的位置。