1 共轭方向的定义
对于正定二次函数,其中是对角阵,对角元均为正数,这种情况下函数关于原点中心对称,每列由一个n元向量组成,向着每个维度,即正交搜索方向,作一次精确线搜索就可以得到最小值的精确解,具有二次终止性。这个过程结合图像不难理解。
若是是对称正定阵,而非对角阵,为了利用这一性质,我们需要将非对角阵变换为对角阵。作变换,则有,D中包含的每两个向量满足:
这样一来,最后就变成了对角矩阵。我们称这样的每两个方向和为共轭方向,经过这样的变换可以将共轭方向变为正交搜索方向。
三维直角坐标系中的正交搜索方向是很容易求取的,而对于非对角正定二次函数,我们主要要确定共轭方向,这相当于是对坐标进行变换后在新的坐标空间内的正交搜索方向。
设为。若存在对称正定矩阵,使得,则称为的平方根矩阵,记为,有变换将正交搜索方向变为共轭方向。
对于秩为n的对称正定矩阵G,共轭方向有n个。
由任意出发,依次沿直线作满足的精确线性搜索,其中(正定二次函数梯度),则搜满n个共轭方向后是线性流形中的极小点。
2 针对二次函数的共轭梯度法
给定初始点,取初始搜索方向为负梯度方向,在后面的迭代中取负梯度方向和前一搜索方向的线性组合作为搜索方向,控制使得共轭性条件满足。
对于共轭方向有,则有,所以。
因此可以得到针对二次函数的共轭梯度法步骤:
- 给定初始点,令
- 计算
- 若,则停止
- 线搜索确定步长
- 求,令,转步2
3 针对一般函数的共轭梯度法
为了使得共轭梯度法适用于一般函数,我们要消除掉迭代公式中的G。
,两边求梯度有,则有,代入的计算公式可以消掉,这种方法被称为HS共轭梯度法,有
HS法的共轭性证明见附录1。由共轭性证明我们可以得到三个结论:
利用以上三个结论可以得到HS共轭梯度法的更多变形,这两种变形产生算法的收敛性是可以得到证明的:
- PRP共轭梯度法:
- FR共轭梯度法:
步骤:
- 给定初始点,精度,令
- 若满足终止准则,则得解,算法终止
- 确定步长
- 令
- 由以上各种方法确定
- 确定,令,转2
4 性能评估
4.1 收敛性
使用精确搜索时,算法的收敛性是可以保证的。(证明见附录2)
对于FR算法,采用非精确线性搜索时,需要使用强Wolfe-Powell条件,且(证明见附录3)
对于PRP算法,采用非精确线性搜索时,需要使用公式:。这是为了使得产生的不为负数,保证下降方向的产生
4.2 其他性能
- 二次终止性:满足,且若矩阵G有r个不同特征值,则算法最多经过r次迭代达到问题的最优解
- 计算量:小,无需计算黑森矩阵
- 储存空间:小,只需记录两点梯度和前一点方向。这使得共轭梯度法适用于解决大规模最优化问题
5 实战测试
对于本文集的第一篇文章深入浅出最优化(1) 最优化问题概念与基本知识中提出的最小二乘问题,的初值均在的范围内随机生成,总共生成100组起点。统计迭代成功(在1000步内得到最优解且单次步长搜索迭代次数不超过1000次)的样本的平均迭代步数、平均迭代时间和得到的最优解及残差平方和最小值。
PRP+:
平均迭代步数 | 平均迭代时间 | 最优解 | 残差平方和最小值 |
---|---|---|---|
17.1 | 0.41s |
FR:
平均迭代步数 | 平均迭代时间 | 最优解 | 残差平方和最小值 |
---|---|---|---|
23.2 | 0.56s |
代码实现
本博客所有代码在https://github.com/HarmoniaLeo/optimization-in-a-nutshell开源,如果帮助到你,请点个star,谢谢这对我真的很重要!
你可以在上面的GitHub链接或本文集的第一篇文章深入浅出最优化(1) 最优化问题概念与基本知识中找到Function.py和lagb.py
import numpy as np
from Function import Function #定义法求导工具
from lagb import * #线性代数工具库
from scipy import linalg
n=2 #x的长度
def myFunc(x): #x是一个包含所有参数的列表
return x[0]**2 + 2*x[1]**2 + 2*x[0] - 6*x[1] +1 #目标方程
x=np.zeros(n) #初始值点
e=0.001
beta1=1
sigma=0.4
rho=0.55
tar=Function(myFunc)
k=0
d=-tar.grad(x)
while tar.norm(x)>e:
a=1
if not (tar.value(x+a*d)<=tar.value(x)+rho*a*dot(turn(tar.grad(x)),d) and \
np.abs(dot(turn(tar.grad(x+a*d)),d))>=sigma*dot(turn(tar.grad(x)),d)):
a=beta1
while tar.value(x+a*d)>tar.value(x)+rho*a*dot(turn(tar.grad(x)),d):
a*=rho
while np.abs(dot(turn(tar.grad(x+a*d)),d))<sigma*dot(turn(tar.grad(x)),d):
a1=a/rho
da=a1-a
while tar.value(x+(a+da)*d)>tar.value(x)+rho*(a+da)*dot(turn(tar.grad(x)),d):
da*=rho
a+=da
lx=x
x=x+a*d
beta=np.max((dot(turn(tar.grad(x)),tar.grad(x)-tar.grad(lx))/(tar.norm(lx)**2),0)) #PRP+
beta=(tar.norm(x)**2)/(tar.norm(lx)**2) #FR
d=-tar.grad(x)+beta*d
k+=1
print(k)
print(x)
附录
使用精确搜索时共轭梯度算法收敛性证明:因为,从而