设目标函数
f
(
x
)
f(\boldsymbol{x})
f(x),
x
∈
R
n
\boldsymbol{x}\in\text{ℝ}^n
x∈Rn,有最小值点
x
0
\boldsymbol{x}_0
x0且二阶可微,则在
x
0
\boldsymbol{x}_0
x0近旁可以用二次型函数
q
(
x
)
=
1
2
x
⊤
H
x
−
x
⊤
g
q(\boldsymbol{x})=\frac{1}{2}\boldsymbol{x}^\top\boldsymbol{H}\boldsymbol{x}-\boldsymbol{x}^\top\boldsymbol{g}
q(x)=21x⊤Hx−x⊤g
其中
g
=
∇
f
(
x
)
\boldsymbol{g}=\nabla f(\boldsymbol{x})
g=∇f(x)为
f
(
x
)
f(\boldsymbol{x})
f(x)的梯度,
H
=
∇
2
f
(
x
)
\boldsymbol{H}=\nabla^2f(\boldsymbol{x})
H=∇2f(x)为
f
(
x
)
f(\boldsymbol{x})
f(x)的Hesse阵,作为
f
(
x
)
f(\boldsymbol{x})
f(x)的近似。一个自然的想法是对二次型函数
q
(
x
)
q(\boldsymbol{x})
q(x)运用共轭梯度算法计算
f
(
x
)
f(\boldsymbol{x})
f(x)的最优值点
x
0
\boldsymbol{x}_0
x0的近似值。
对此,需克服两个困难。其一,每次迭代时
f
(
x
)
f(\boldsymbol{x})
f(x)在上一个迭代点处的Hesse阵
H
\boldsymbol{H}
H必须重新计算,这将花费很大的运算量。注意到共轭梯度算法中涉及
H
\boldsymbol{H}
H计算的有两处:搜索步长
α
k
=
−
g
k
⊤
d
k
d
k
⊤
H
d
k
\alpha_k=\frac{-\boldsymbol{g}_k^\top\boldsymbol{d}_k}{\boldsymbol{d}_k^\top\boldsymbol{Hd}_k}
αk=dk⊤Hdk−gk⊤dk及共轭方向组合系数
β
k
=
g
k
+
1
⊤
H
d
k
d
k
⊤
H
d
k
\beta_k=\frac{\boldsymbol{g}_{k+1}^\top\boldsymbol{Hd}_{k}}{\boldsymbol{d}_{k}^\top\boldsymbol{Hd}_{k}}
βk=dk⊤Hdkgk+1⊤Hdk。如果能在这两个计算中消除
H
\boldsymbol{H}
H,将能大大改善计算效率。
对于
α
k
\alpha_k
αk,实质上其为一元函数
ϕ
k
(
α
)
=
f
(
x
k
+
α
d
k
)
\phi_k(\alpha)=f(\boldsymbol{x}_k+\alpha\boldsymbol{d}_k)
ϕk(α)=f(xk+αdk)最小值点,即
α
k
=
arg
min
α
>
0
ϕ
(
α
)
,
k
=
1
,
2
,
⋯
,
n
.
\alpha_k=\arg\min_{\alpha>0}\phi(\alpha),k=1,2,\cdots,n.
αk=argα>0minϕ(α),k=1,2,⋯,n.
为在
β
k
\beta_k
βk的计算中消除
H
\boldsymbol{H}
H,按Fletcher-Reeves公式通过代换计算可得
β
k
=
g
k
+
1
⊤
(
g
k
+
1
−
g
k
)
g
k
⊤
g
k
,
k
=
1
,
2
,
⋯
,
n
.
\beta_k=\frac{\boldsymbol{g}_{k+1}^\top(\boldsymbol{g}_{k+1}-\boldsymbol{g}_k)}{\boldsymbol{g}_k^\top\boldsymbol{g}_k},k=1,2,\cdots,n.
βk=gk⊤gkgk+1⊤(gk+1−gk),k=1,2,⋯,n.
将
α
k
\alpha_k
αk及
β
k
\beta_k
βk代入共轭向量计算式,得
d
k
+
1
=
−
g
k
+
β
k
d
k
\boldsymbol{d}_{k+1}=-\boldsymbol{g}_k+\beta_k\boldsymbol{d}_k
dk+1=−gk+βkdk,修改共轭梯度算法——称为FR共轭梯度算法,并实现为如下Python函数
import numpy as np
from scipy.optimize import minimize_scalar,OptimizeResult
def conjFR(f,x1,gtol,**options):
n=x1.size
xk=x1
gk=grad(f,xk)
dk=-gk
phi=lambda a: f(xk+a*dk)
k=1
while np.linalg.norm(gk)>=gtol:
ak=(minimize_scalar(phi)).x
xk=xk+ak*dk
gk1=grad(f,xk)
if k%n==0:
bk=0
else:
bk=np.matmul(gk1,gk1)/np.matmul(gk,gk)
dk=-gk1+bk*dk
gk=gk1
k+=1
bestx=xk
besty=f(xk)
return OptimizeResult(fun=besty, x=bestx, nit=k)
程序的第3~23行定义了实现FR共轭梯度算法的conjFR函数,参数f表示目标函数
f
(
x
)
f(\boldsymbol{x})
f(x),x1表示初始迭代点
x
1
\boldsymbol{x}_1
x1,gtol表示容错误差
ε
\varepsilon
ε,options实现minimize与本函数的信息交换机制。
第4~9行执行初始化操作:第4行将可行解位数赋予n。第5行将迭代点xk初始化为x1。第6行调用计算函数梯度的grad(详见博文《最优化方法Python计算:n元函数梯度与Hesse阵的数值计算》)计算目标函数f在当前迭代点xk处的梯度
g
1
=
∇
f
(
x
1
)
\boldsymbol{g}_1=\nabla f(\boldsymbol{x}_1)
g1=∇f(x1)
赋予gk。第7行将表示共轭方向的dk初始化为
−
g
1
-\boldsymbol{g}_1
−g1。第8行定义函数
ϕ
(
α
)
=
f
(
x
k
+
α
d
k
)
\phi(\alpha)=f(\boldsymbol{x}_k+\alpha\boldsymbol{d}_k)
ϕ(α)=f(xk+αdk)
为phi。第9行将迭代次数k初始化为1。
第10~20行的while循环执行迭代操作:第11行调用minimize_scalar(第2行导入)计算
arg
min
α
>
0
ϕ
(
α
)
\arg\min\limits_{\alpha>0}\phi(\alpha)
argα>0minϕ(α)
赋予ak。第12行计算迭代点
x
k
+
1
=
x
k
+
α
k
d
k
\boldsymbol{x}_{k+1}=\boldsymbol{x}_k+\alpha_k\boldsymbol{d}_k
xk+1=xk+αkdk
更新xk。第13行计算
g
k
+
1
=
∇
f
(
x
k
+
1
)
\boldsymbol{g}_{k+1}=\nabla f(\boldsymbol{x}_{k+1})
gk+1=∇f(xk+1)
赋予gk1。第14~17行的if-else分支根据迭代次数k是否为n的整数倍决定共轭方向
d
k
\boldsymbol{d}_k
dk的组合系数
β
k
\beta_k
βk的计算:若是,则
β
k
=
0
\beta_k=0
βk=0
否则
β
k
=
g
k
+
1
⊤
g
k
+
1
g
k
⊤
g
k
\beta_k=\frac{\boldsymbol{g}_{k+1}^\top\boldsymbol{g}_{k+1}}{\boldsymbol{g}_{k}^\top\boldsymbol{g}_{k}}
βk=gk⊤gkgk+1⊤gk+1
将算得的
β
k
\beta_k
βk赋予bk。第18行计算
d
k
+
1
=
−
g
k
+
1
+
β
k
d
k
\boldsymbol{d}_{k+1}=-\boldsymbol{g}_{k+1}+\beta_{k}\boldsymbol{d}_k
dk+1=−gk+1+βkdk
更新dk。第19行用
g
k
+
1
\boldsymbol{g}_{k+1}
gk+1更新gk。第20行将迭代次数k自增1。循环往复,直至条件
∥
g
k
∥
<
ε
\lVert\boldsymbol{g}_k\rVert<\varepsilon
∥gk∥<ε
成立。
第21~23行用
f
(
x
k
)
f(\boldsymbol{x}_k)
f(xk),
x
k
\boldsymbol{x}_k
xk及
k
k
k构造OptimizeResult(第2行导入)对象,并返回。
例1 给定初始点
x
1
=
(
2
1
)
\boldsymbol{x}_1=\begin{pmatrix}2\\1\end{pmatrix}
x1=(21),分别以容错误差
ε
=
1
0
−
3
\varepsilon=10^{-3}
ε=10−3和
ε
=
1
0
−
5
\varepsilon=10^{-5}
ε=10−5用conjFR方法计算Rosenbrock函数
f
(
x
)
=
100
(
x
2
−
x
1
2
)
2
+
(
1
−
x
1
)
2
f(\boldsymbol{x})=100(x_2-x_1^2)^2+(1-x_1)^2
f(x)=100(x2−x12)2+(1−x1)2的最优解。
解:下列代码完成计算。
import numpy as np #导入numpy
from scipy.optimize import minimize,rosen #导入minimize,rosen
x=np.array([2,1]) #设置初始迭代点
res=minimize(rosen,x,method=conjFR,options={'gtol':1e-3})
print(res)
res=minimize(rosen,x,method=conjFR,options={'gtol':1e-5})
print(res)
程序的第4、6行调用minimize函数,传递rosen和x给参数fun和x0,传递conjFR给参数method,并用options机制向conjFR的gtol参数分别传递 1 0 − 3 10^{-3} 10−3和 1 0 − 5 10^{-5} 10−5,计算最优解。运行程序,输出
fun: 1.7856398066667848e-08
nit: 10
x: array([1.00013352, 1.00026759])
fun: 1.7767405467097918e-18
nit: 12
x: array([1., 1.])
可见对FR共轭梯度算法而言,容错误差对解的精度有较大影响,对算法效率(迭代次数)的影响并不明显。可见,共轭梯度算法的效率远比梯度下降算法的高(参见博文《最优化方法Python计算:梯度下降搜索算法》)。
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!