在之前的leetcode周赛里有这么一题,要求求平面上某点,到各个给定点的欧几里得距离之和最小,即求给定函数
f
(
x
,
y
)
=
∑
i
=
1
n
(
x
−
x
i
)
2
+
(
y
−
y
i
)
2
f(x,y)=\sum_{i=1}^n\sqrt{(x-x_i)^2+(y-y_i)^2}
f(x,y)=∑i=1n(x−xi)2+(y−yi)2在平面上的最小值。频道里的大佬说了能直接调包来做,查了一下,python有scipy的optimize库可以用不同的算法来求解函数局域最小值。
好的,非常感谢你的什么也没讲。那么就从这些缩写开始出发,开始摸一下求局域最小值。
最速下降法
最速下降法顾名思义,就是在
(
x
k
,
y
k
)
(x_k,y_k)
(xk,yk)处,沿着函数
f
(
x
,
y
)
f(x,y)
f(x,y)下降最快的方向,即负梯度方向走上一段。迭代公式为
x
⃗
k
+
1
=
x
⃗
k
−
ρ
k
g
⃗
k
\vec{x}_{k+1}=\vec{x}_{k}-\rho_k\vec{g}_{k}
xk+1=xk−ρkgk.
步长
ρ
k
\rho_k
ρk需满足
f
(
x
⃗
k
+
1
)
<
f
(
x
⃗
)
f(\vec{x}_{k+1})<f(\vec{x})
f(xk+1)<f(x)
我们不妨先试着使用Leetcode上AC了的算法,使用固定步长的方法来求解上述Rosenbrock函数的最小值,即初始步长固定为
ρ
0
=
0.03
\rho_0=0.03
ρ0=0.03,当
f
(
x
⃗
k
+
1
)
>
f
(
x
⃗
k
)
f(\vec{x}_{k+1})>f(\vec{x}_{k})
f(xk+1)>f(xk)时,将
ρ
\rho
ρ减小一半直至步长满足函数下降要求。这里有一点需要注意,因为Rosenbrock函数的在山谷之外其梯度的模特别大,所以我们应该使用的是单位长度的梯度
g
⃗
k
\vec{g}_k
gk来计算下一步的位置。(参考:
x
=
1.05
,
y
=
1.05
x=1.05,y=1.05
x=1.05,y=1.05时,对应梯度的模为
∣
g
⃗
k
∣
=
24.5127
\lvert \vec{g}_k \rvert =24.5127
∣gk∣=24.5127)
结果:
不出意料的是在迭代10万次之后,函数甚至离目标值还有很大一段差距,在查看步长迭代的情况后,猜测是因为步长变化太剧烈,使得函数下降太慢:
那么接下来对步长提出要求,不仅需要使得函数严格递减,还要使函数递减到该方向上的最小值。也就是找到
ρ
\rho
ρ使得
m
i
n
(
f
(
x
⃗
k
−
ρ
g
⃗
k
)
)
min(f(\vec{x}_k-\rho\vec{g}_k))
min(f(xk−ρgk))。
令
g
(
ρ
)
=
f
(
x
⃗
k
−
ρ
g
⃗
k
)
g(\rho)=f(\vec{x}_k-\rho\vec{g}_k)
g(ρ)=f(xk−ρgk),则
g
(
ρ
)
g(\rho)
g(ρ)的最小值在
d
d
ρ
g
(
x
)
=
∇
f
(
x
⃗
k
−
ρ
g
⃗
k
)
T
g
⃗
k
=
0
\frac{d}{d\rho}g(x)=\nabla f(\vec{x}_k-\rho\vec{g}_k)^T\vec{g}_k=0
dρdg(x)=∇f(xk−ρgk)Tgk=0处取到。这只需我们解一个一元方程即可得到最适宜步长
ρ
\rho
ρ。
在求解
ρ
\rho
ρ时,有个较为实用的方法,即将
f
(
x
)
f(x)
f(x)展开为二次型,
f
∗
(
x
⃗
k
+
δ
⃗
)
=
1
2
δ
⃗
T
H
δ
⃗
+
g
⃗
T
δ
⃗
+
f
(
x
⃗
k
)
f^*(\vec{x}_k+\vec{\delta})=\frac{1}{2}\vec{\delta}^TH\vec{\delta}+\vec{g}^T\vec{\delta}+f(\vec{x}_k)
f∗(xk+δ)=21δTHδ+gTδ+f(xk)
若海森矩阵
H
H
H为正定矩阵,则
∇
f
∗
(
x
⃗
k
−
ρ
g
⃗
k
)
T
g
⃗
k
=
g
⃗
k
+
k
T
⋅
g
⃗
k
=
(
H
(
x
⃗
−
ρ
g
⃗
k
)
+
g
⃗
k
)
T
g
⃗
k
=
(
H
x
⃗
+
b
⃗
−
ρ
H
g
⃗
k
)
T
g
⃗
k
=
(
g
⃗
k
−
ρ
H
g
⃗
k
)
T
g
⃗
k
=
0
\begin{aligned} \nabla & f^*(\vec{x}_k-\rho\vec{g}_k)^T\vec{g}_k\\ = & \vec{g}_{k+k}^T\cdot\vec{g}_k\\ = & (H(\vec{x}-\rho\vec{g}_k)+\vec{g}_k)^T\vec{g}_k\\ = & (H\vec{x}+\vec{b}-\rho H\vec{g}_k)^T\vec{g}_k\\ = & (\vec{g}_k-\rho H\vec{g}_k)^T\vec{g}_k =0 \end{aligned}
∇====f∗(xk−ρgk)Tgkgk+kT⋅gk(H(x−ρgk)+gk)Tgk(Hx+b−ρHgk)Tgk(gk−ρHgk)Tgk=0
于是有
ρ
=
g
⃗
k
T
g
⃗
k
g
⃗
k
T
H
g
⃗
k
\rho=\dfrac{\vec{g}_k^T\vec{g}_k}{\vec{g}_k^TH\vec{g}_k}
ρ=gkTHgkgkTgk,此时不再需要计算单位长度的梯度,而是使用
g
⃗
k
\vec{g}_k
gk直接参与计算,在基础上重新计算Rosenbrock函数的最小值,则有:
可以很明显的看出在只使用原来的1/4迭代次数,就达到了最小值。在某些点处可以甚至有一个很明显的跳跃。对比了步长
ρ
(
k
)
\rho(k)
ρ(k),发现固定步长法输的透彻。
牛顿法
在上述讨论最速下降法的时候,我们很容易发现面对这种存在盆地的函数,最速下降法收敛速度及其缓慢,那么从上面的函数展开式出发我们引入牛顿法。
将
f
(
x
⃗
)
f(\vec{x})
f(x)在
x
⃗
k
\vec{x}_k
xk处展开为二次型,
f
∗
(
x
⃗
k
+
δ
⃗
)
=
1
2
δ
⃗
T
H
δ
⃗
+
g
⃗
T
δ
⃗
+
f
(
x
⃗
k
)
f^*(\vec{x}_k+\vec{\delta})=\frac{1}{2}\vec{\delta}^TH\vec{\delta}+\vec{g}^T\vec{\delta}+f(\vec{x}_k)
f∗(xk+δ)=21δTHδ+gTδ+f(xk)
在函数局域最小值点有
∇
f
∗
(
x
⃗
k
+
1
)
=
0
=
H
k
δ
⃗
+
g
⃗
k
=
0
\begin{aligned} \nabla & f^*(\vec{x}_{k+1})=0\\ &=H_k\vec{\delta}+\vec{g}_k\\ &=0 \end{aligned}
∇f∗(xk+1)=0=Hkδ+gk=0
得迭代公式
x
⃗
k
+
1
=
x
⃗
k
−
H
k
−
1
g
⃗
k
\vec{x}_{k+1}=\vec{x}_k-H^{-1}_k\vec{g}_k
xk+1=xk−Hk−1gk,尝试一下:
下降速度之快出乎我的意料,观察一下函数曲线
f
(
x
⃗
k
)
f(\vec{x}_k)
f(xk):
第三次迭代的时候出现了一个上升,那么得到的第一个结论就是:牛顿法并不是一个下降算法,即他并不保证每一步的搜索都能保证函数值下降。
具体到这个问题中,原因是虽然搜索的方向
d
⃗
k
\vec{d}_k
dk确实是函数下降方向,但是由于牛顿法的步长默认为1,出现了虽然是展开函数
f
∗
(
x
⃗
)
f^*(\vec{x})
f∗(x)的最小值点
x
⃗
∗
\vec{x}^*
x∗,但是不能使原函数
f
(
x
⃗
)
f(\vec{x})
f(x)下降。
另一个可能的会使函数值不降反升的可能是,当前点远离最小值点
x
⃗
∗
\vec{x}^*
x∗使得海森矩阵
H
H
H并非正定矩阵,则搜索方向
d
k
=
−
H
k
−
1
g
k
d_k=-H_k^{-1}g_k
dk=−Hk−1gk不一定是函数的下降方向,即
g
k
T
d
k
<
0
g_k^Td_k<0
gkTdk<0
还有一个关于牛顿法的较为严重的问题是,函数可能不能二阶可微,此时无法通过牛顿法求解。
为了解决上述几个问题,分别引入了带阻尼的牛顿法(解决步长问题),拟牛顿法(解决求海森矩阵以及海森矩阵不正定的问题)