特征缩放
特征缩放描述的是如果我们有一个机器学习的问题,这个问题有多个特征,如果你能够确保这些不同特征的取值都处于一个相近的范围内,那么梯度下降法就能够更快地收敛。
具体来说,假设我们有一个具有两个特征的机器学习问题,其中
x
1
x_1
x1 是房子的大小,它的取值在
0
−
2000
0-2000
0−2000之间;
x
2
x_2
x2 是房间卧室的数量,它的取值在
1
−
5
1-5
1−5之间。
如果你画出此时代价函数的图像,那么就会像上图中所示的那样(我们之前介绍过两个特征对应的代价函数图像是三维空间的曲面,所以上图展示的是代价函数的等高线),你会发现代价函数等高线的形状是一种歪斜的椭圆形,如果你在这种代价函数上运行梯度下降的话,梯度下降会耗费一定的时间,因为梯度会在等高线之间来回波动,最终才收敛到全局最小值。这就好比是走“S”型路线下山,这当然会比走近似直线型耗费更多的时间。
最大值约束
此时,一种有效的做法就是进行特征缩放,具体来说,如果你将 x 1 x_1 x1 定义为房子的大小除以 2000 2000 2000,即除以房子大小的最大值;将 x 2 x_2 x2 为房间卧室的数量除以 5 5 5,即除以卧室数量的最大值,那么我们会发现此时 x 1 x_1 x1 和 x 2 x_2 x2 的取值范围变成了 0 ≤ x 1 , x 2 ≤ 1 0\le x_1,x_2 \le 1 0≤x1,x2≤1 ,也就是说,我们通过这样的操作使得特征的取值范围处在了一个相近甚至相同的区间内,这样的操作就叫做特征缩放。
观察上图,可以发现,在进行特征缩放之后,我们得到的代价函数的图像更加平滑了,这就会使得在进行梯度下降时,梯度下降的路线更趋向于一条直线,也就是说,梯度下降就会更快地收敛。
当我们进行特征缩放时,我们通常的目的是尽量将特征的取值约束到
[
−
1
,
1
]
[-1,1]
[−1,1] 的范围内,具体来说,我们并不是一定要将所有特征的取值严格约束到这个范围内,而是尽量让它们的取值在这个范围附近,比如说,对于
−
0.5
≤
x
1
≤
0.5
-0.5\le x_1 \le 0.5
−0.5≤x1≤0.5,对于
−
2
≤
x
2
≤
0.5
-2\le x_2 \le 0.5
−2≤x2≤0.5,对于
2
≤
x
3
≤
2.5
2\le x_3 \le 2.5
2≤x3≤2.5,这些都是可行的;而对于
−
100
≤
x
4
≤
100
-100\le x_4 \le 100
−100≤x4≤100,对于
−
0.005
≤
x
5
≤
0.005
-0.005\le x_5 \le 0.005
−0.005≤x5≤0.005,这些就不可行,因为它们与
[
−
1
,
1
]
[-1,1]
[−1,1] 的差距显然是很大的,按照吴佬的经验,这个范围最大可在
[
−
3
,
3
]
[-3,3]
[−3,3],最小可在
[
−
1
3
,
1
3
]
[-\frac 1 3,\frac1 3]
[−31,31]
均值归一化
除了将特征除以最大值以外,在特征缩放中,有时候我们也会进行一个称为均值归一化的操作
具体来说,如果我们有一个特征
x
i
x_i
xi ,那么我们使用
x
i
−
u
i
x_i-u_i
xi−ui 来代替
x
i
x_i
xi 来使得特征量的值可能取到
0
0
0 ,其中
u
i
u_i
ui 是训练集中特征
x
i
x_i
xi 的平均值,然后再将
x
i
x_i
xi 定义为
x
i
−
u
i
s
i
\Large\frac {x_i-u_i} {s_i}
sixi−ui,其中,
s
i
s_i
si 是特征
x
i
x_i
xi 的取值范围的大小,即取值范围的最大值减去最小值。
对于之前的两个特征,我们可以对它们进行均值归一化的操作,即将 x 1 x_1 x1 定义为 x 1 − 1000 2000 \Large\frac {x_1-1000} {2000} 2000x1−1000,将 x 2 x_2 x2 定义为 x 2 − 2 4 \Large\frac {x_2-2} {4} 4x2−2,那么我们会发现此时 x 1 x_1 x1 和 x 2 x_2 x2 的取值范围变成了 − 0.5 ≤ x 1 , x 2 ≤ 0.5 -0.5\le x_1,x_2 \le 0.5 −0.5≤x1,x2≤0.5 。
上面只是在进行特征缩放时的两种操作方法,对于特征缩放我们并没有严格的方法规定,只要将特征转换到相近似的范围就都是可以的,所以实际上特征缩放并不需要太精确,只是为了让梯度下降运行的更快一点,迭代的次数更少一点而已
学习率
如上图所示,我们梯度下降的参数更新方程
θ
j
:
=
θ
j
−
α
∂
∂
θ
j
J
(
θ
)
\theta_j:=\theta_j-\alpha{\large\frac {\partial} {\partial\,\theta_j}}J(\theta)
θj:=θj−α∂θj∂J(θ),其中,我们称
α
\alpha
α 为学习率,我们在介绍梯度下降法时提到了,学习率的取值是一个问题。比如,当
α
\alpha
α 的取值太大时,可能会导致梯度无法收敛,甚至发散;当
α
\alpha
α 的取值太小时,则会导致梯度收敛速度缓慢。
所以讨论如何选择学习率 α \alpha α 是非常必要的。同时,我们还会讨论如何对梯度下降进行“调试”,以保证我们知道梯度下降是否在正确工作。
梯度下降Debugging
首先,我们来讨论如何确保梯度下降在正常工作。
梯度下降算法所做的事情就是为你找到一个 θ \theta θ 值并且希望它能够最小化代价函数 J ( θ ) J(\theta) J(θ),即我们的目标函数是 θ m i n \large_{\;\;\theta}^{min} θmin J ( θ ) J(\theta) J(θ)
绘制曲线
根据吴佬的介绍,我们可以在梯度下降算法运行时,绘制出代价函数
J
(
θ
)
J(\theta)
J(θ)的值。
如上图所示,其中,横轴代表梯度下降算法的迭代次数,纵轴代表代价函数
J
(
θ
)
J(\theta)
J(θ) 的值,随着梯度下降算法的运行,我们可能会得到上图中的蓝色曲线,曲线上的一点代表着在对应的迭代次数
x
x
x 之后,我们得到的代价函数
J
(
θ
)
J(\theta)
J(θ) 的值
y
y
y。
显然,在经过 x x x 次迭代之后,根据参数更新方程,我们能够得到参数 θ \theta θ 的值,然后我们将此时得到的参数 θ \theta θ 代入代价函数中即可得到此时 J ( θ ) J(\theta) J(θ) 的值,所以这条曲线代表着梯度下降的每步迭代之后代价函数 J ( θ ) J(\theta) J(θ) 的值。
那么,很显然,如果梯度下降算法正常工作的话,在每次迭代之后,代价函数 J ( θ ) J(\theta) J(θ) 的值都应该减小,对应曲线的斜率应该是逐次趋向于 0 0 0 的,所以当梯度下降达到收敛时,曲线应该是近似于一条水平线,即随着迭代次数的增加,代价函数的值几乎都没有什么变化,就说明此时梯度下降已经收敛到局部最小值或者全局最小值,所以通过这条曲线还可以帮助我们判断梯度下降算法是否已经达到收敛。
需要注意的是,对于每一个特定的问题,梯度下降算法所需要的迭代次数可能会相差很大,具体来说,可能对于一个问题,梯度下降只需要 30 30 30 次迭代即可达到收敛,然而对于另一个问题,梯度下降可能需要 3000 3000 3000 次迭代才可达到收敛,实际上我们很难提前判断出梯度下降需要多少次迭代才能收敛,所以通过绘制代价函数随迭代次数变化的曲线能够帮助我们很好的判断梯度下降是否达到收敛。
自动测试
另外,我们也可以通过一些自动收敛测试来告诉你梯度下降算法是否已经收敛。
下面是自动收敛测试一个非常典型的例子:
如果代价函数
J
(
θ
)
J(\theta)
J(θ) 一步迭代后的下降小于一个很小的值
ε
\varepsilon
ε,比如上图中的
ε
=
1
e
−
3
\varepsilon=1e-3
ε=1e−3,那么,此时测试就判断函数已经收敛。很显然,对应在代码中,我们只需要在每次迭代后加入判断语句即可实现自动测试的功能。
但实际上,选择出一个合适的阈值 ε \varepsilon ε 是相当困难的,因此,为了检查梯度下降是否收敛,我们应该更倾向于绘制出代价函数随迭代次数变化的曲线,而不是依靠自动测试。
绘制出代价函数的变化曲线还能够帮助我们判断梯度下降是否在正常工作,比如对于上图中的曲线,可以看到,随着迭代次数的增加,代价函数的值在逐渐增大,显然这与我们的目标相违背,说明此时梯度下降并没有在正常工作,遇到这种情况,一般的解决方法就是使用更小的学习率
α
\alpha
α,一般来说,只要梯度下降算法没有在正常工作,往往都是因为学习率
α
\alpha
α 过大导致的。
从数学上可以严格的证明这一点,即在线性回归中,只要学习率
α
\alpha
α 足够小,代价函数在每次迭代后应该都会减小,即梯度下降收敛的必然性,所以我们说大多数梯度下降没有正常工作的情况都是由于学习率
α
\alpha
α 过大导致的;但与之对应的弊端就是如果
α
\alpha
α 太小,梯度下降收敛的速度自然也会非常慢。
最后,总结一下学习率对于梯度下降的影响:
当
α
\alpha
α 的取值太大时,可能会导致梯度无法收敛,甚至发散;
当
α
\alpha
α 的取值太小时,则会导致梯度收敛速度缓慢。
学习率的设置
在选择学习率
α
\alpha
α 的值时,
我们可以从小到大,按照一定的间隔对
α
\alpha
α 进行取值,比如上图所示,按照三倍的间隔来取值;
然后在每种
α
\alpha
α 的取值下,绘制出代价函数随迭代次数变化的曲线,来判断此时梯度下降是否在正常工作,比如当
α
=
0.003
\alpha=0.003
α=0.003 时,如果判断此时梯度下降在正常工作,那么就再取
α
=
0.01
\alpha=0.01
α=0.01 ,再判断梯度下降是否正常工作;
直到
α
\alpha
α 取某一个值时,梯度下降不正常工作了,那么我们就取这个
α
\alpha
α 值的前一个取值当作我们最终的学习率
α
\alpha
α ,比如当
α
=
0.1
\alpha=0.1
α=0.1 时,我们判断出此时梯度下降不在正常工作,那么,我们就取
α
=
0.03
\alpha=0.03
α=0.03 作为最终的学习率,这样我们就能得到一个合理、不错的学习率啦@~@