前言:
Newton和阻尼Newton收敛速度快,但需计算 Hesse 矩阵的逆,,计算量大。现有 n 阶正定矩阵
近似代替 Hesse 矩阵的逆
,即
,搜索方向是
由此产生的方法称为变尺度法,
称为尺度矩阵。
构造尺度矩阵的原则:
1.拟牛顿性质:
在 点处对函数
做二阶 Taylor 展开:
略去高阶项:
两端求导:
令 ,则
记 ,那么
并忽略高阶无穷小量,则有:
又因为 Hesse 矩阵 对称正定(
),则:
(注: 不唯一)
2.二次收敛性:
,A 对称正定,把算法用于 n 元正定二次函数时,至多 n 次迭代达到极小点,故:
构造的搜索方向 是一组 A 的共轭向量组且
3.稳定性:
若忽略计算过程的舍入误差,在算法的每个迭代点 都能选择步长,使得下个迭代点
处的函数值下降,则称此算法是稳定的。
是下降方向,可以保证算法稳定
对称正定
总结:
综合来看,依据三个原则:拟牛顿性质,二次收敛性,稳定性, 需满足对应的三个条件。这个方法最早由Davidon在1959年提出,1963年Fletcher和Powell又加以改进,因此称之为DFP算法,DFP算法是目前使用最多的无约束最优化算法之一。
DFP算法:
Hk的构造方法:
对称正定满足拟牛顿性质 ,
设:
其中,,
是常数,
是 n 维列向量
对称正定满足拟牛顿性质
,
则有(全部右乘 ):
由于 并不唯一,故简单的取:
令,
,
,
DFP算法定理:
- 若
,i=1,2,...,n,则DFP算法构造的矩阵
(i=1,2,...,n)为对称正定矩阵。
- 设用 DFP 算法求解下列问题,
,其中 A 为 n 阶对称正定矩阵,有 DFP 方法产生的搜索方向为
,对应的尺度矩阵为
则有:
,
,
,
DFP算法步骤:
步骤1:选定初始点 ,初始矩阵
,
步骤2:如果 ,算法停止,
,否则转步骤3.
步骤3:取
步骤4:精确一维搜索找最佳步长 ,令
.
步骤5:如果 ,算法停止,
,否则转步骤6.
步骤6:如果 k=n ,令,转步骤4;否则转步骤7.
步骤7:令 ,
,计算
,和
,k=k+1,转步骤4.
例题分析:
同样的,由于前面的太过抽象,我们来用一道例题加深对该算法的理解
例题:用 DFP 算法求 ,已知初始点
,迭代精度
=0.001.
解:计算函数 的梯度函数:
第一次迭代:
,
,
令
不满足精度,继续迭代。
第二次迭代:
,
令
令
算法终止,得到最优解
算法代码:
'''
变尺度算法 (DFP算法)
2023.11.5
'''
import numpy as np
from sympy import symbols, diff, solve
x1 = symbols("x1")
x2 = symbols("x2")
λ = symbols("λ")
f = 2 * x1 ** 2 + x2 ** 2 - 4 * x1 + 2
def DFP(x1_init, x2_init, ε):
# 一阶求导
grad_1 = diff(f, x1)
grad_2 = diff(f, x2)
x1_curr = x1_init
x2_curr = x2_init
first_grad_1_value = grad_1.subs({x1: x1_curr, x2: x2_curr})
first_grad_2_value = grad_2.subs({x1: x1_curr, x2: x2_curr})
g1 = np.array([first_grad_1_value, first_grad_2_value], dtype=float)
norm_result_1 = np.linalg.norm(g1, ord=2, axis=0)
if norm_result_1 <= ε:
print("算法停止,该精度下的最优点是[%f,%f]" % (float(x1_curr), float(x2_curr)))
print("最优解为{}".format(f.subs({x1: x1_curr, x2: x2_curr})))
else:
H1 = np.array([[1, 0], [0, 1]])
p1 = -np.dot(H1, g1)
x1_new = x1_curr + λ * p1[0]
x2_new = x2_curr + λ * p1[1]
f_new = f.subs({x1: x1_new, x2: x2_new})
grad_3 = diff(f_new, λ)
λ_value = solve(grad_3, λ)[0]
x1_curr = x1_new.subs(λ, λ_value)
x2_curr = x2_new.subs(λ, λ_value)
print("第{}次迭代".format(1), "当前最优点为[%f,%f]" % (float(x1_curr), float(x2_curr)))
second_grad_1_value = grad_1.subs({x1: x1_curr, x2: x2_curr})
second_grad_2_value = grad_2.subs({x1: x1_curr, x2: x2_curr})
g2 = np.array([second_grad_1_value, second_grad_2_value], dtype=float)
norm_result_2 = np.linalg.norm(g2, ord=2, axis=0)
if norm_result_2 <= ε:
print("算法停止,该精度下的最优点是[%f,%f]" % (float(x1_curr), float(x2_curr)))
print("最优解为{}".format(f.subs({x1: x1_curr, x2: x2_curr})))
else:
DeltaX = np.array([λ_value * p1[0], λ_value * p1[1]], dtype=float)
DeltaG = g2 - g1
H2 = H1 + np.dot(DeltaX, np.transpose(DeltaX)) / np.dot(np.transpose(DeltaG), DeltaX) - np.dot(( np.dot(H1 , DeltaG) , np.transpose(DeltaG)), H1) / np.dot(np.dot(np.transpose(DeltaG), H1), DeltaG)
'''
H2 = H1 + DeltaX * np.transpose(DeltaX) / (np.transpose(DeltaG) * DeltaX) - H1 * DeltaG * np.transpose(
DeltaG) * H1 / (np.transpose(DeltaG) * H1 * DeltaG)
H2 = H1 + np.outer(DeltaX, DeltaX) / (np.dot(np.transpose(DeltaG), DeltaX)) - np.dot(H1, np.dot(DeltaG, np.transpose(DeltaG))) * H1 / (np.dot(np.transpose(DeltaG),np.dot(H1, DeltaG)))
'''
p2 = -np.dot(H2, g2)
x1_new = x1_curr + λ * p2[0]
x2_new = x2_curr + λ * p2[1]
f_new = f.subs({x1: x1_new, x2: x2_new})
grad_3 = diff(f_new, λ)
λ_value = solve(grad_3, λ)[0]
x1_curr = x1_new.subs(λ, λ_value)
x2_curr = x2_new.subs(λ, λ_value)
print("第{}次迭代".format(2), "当前最优点为[%f,%f]" % (float(x1_curr), float(x2_curr)))
print("最优解为{}".format(f.subs({x1: x1_curr, x2: x2_curr})))
grad_1_value = grad_1.subs({x1: x1_curr, x2: x2_curr})
grad_2_value = grad_2.subs({x1: x1_curr, x2: x2_curr})
g3 = np.array([grad_1_value, grad_2_value], dtype=float)
norm_result_3 = np.linalg.norm(g3, ord=2, axis=0)
if norm_result_3 <= ε:
print("算法停止,该精度下的最优解是[%f,%f]" % (float(x1_curr), float(x2_curr)))
print("最优解为{}".format(f.subs({x1: x1_curr, x2: x2_curr})))
return x1_curr, x2_curr
result = DFP(2, 1, 0.001)
该代码所运算的结果为:
第1次迭代 当前最优点为[0.888889,0.444444]
第2次迭代 当前最优点为[1.045204,0.034471]
最优解为0.00527512053991046
(注:这里由于内部存储数据类型的不同,导致存在一定的误差)
总结:
1)如果 能保持对称正定矩阵,则 DFP 算法具有二次终止性
2)对严格凸函数,DFP 算法具有全局收敛性
3) 具有对称正定继承性
4)稳定性不够好
5)占用计算机内存单元多
为此由Broyden,Fletcher,Goldfarb和Shanno于1970年提出的变尺度算法 BFGS , BFGS法比DFP法更稳定,超线性收敛。
(行文中若有纰漏,希望大家指正)