DFP算法(Davidon-Fletcher-Powell algorithm)一种秩2拟牛顿法.由戴维登(Davidon, W. D.)于1959年导出,并由弗莱彻(Fletcher,R.)和鲍威尔(Powe11,M. J. D.)于1963年进行了改善.
对函数
f(x)
在
x=xk+1
处进行泰勒展开到二阶:
对上式求导并令其为0,由于 f(x) 中的 x 是一个向量,
令 gTk+1=∇f(xk+1)=f′(xk+1) ,表示的是目标函数在 xk+1 的梯度,是一个向量。 Gk+1=∇2f(xk+1)=f′′(xk+1)(x−xk+1)2 表示的是目标函数在 xk+1 处的Hesse矩阵。
求导后得:
在基本牛顿法中,取得最值的点处的导数值为0,即上式左侧为0。则:
求出其中的 x :
从上式中发现,在牛顿法中要求Hesse矩阵是可逆的。
当
x=xk
时,上式为(拟牛顿方程):
此时,是否可以通过 xk,xk+1,∇f(xk),∇f(xk+1) 模拟出Hesse矩阵的构造过程?此方法便称为拟牛顿法(QuasiNewton),上式称为拟牛顿方程。
DFP拟牛顿法
DFP拟牛顿法简介
对于拟牛顿方程:
化简可得:
令 Hk+1≜G−1k+1 ,可以得到:
在DFP校正方法中,假设:
DFP校正方法的推导
令:
Ek=αukuTk+βvkvTk
,其中
uk,vk
均为
n×1
的向量。其中:
则对于
Hk+1[∇f(xk+1)−∇f(xk)]=xk+1−xk
可以简化为:
将 Hk+1=Hk+Ek 代入上式:
将 Ek=αukuTk+βvkvTk 代入上式:
已知: uTkyk,vTkyk 为实数, sk−Hkyk 为 n×1 的向量。上式中,参数 α,β 解的可能性有很多,我们取特殊的情况,假设 uk=rHkyk,vk=θsk 。则:
代入上式:
令 αr2(yTkHkyk)+1=0,βθ2(sTkyk)−1=0 ,则:
则最终的DFP校正公式为:
DFP拟牛顿法的算法流程
设
Hk
对称正定,
Hk+1
由上述的DFP校正公式确定,那么
Hk+1
对称正定的充要条件是
sTkyk>0
。
Armijo搜索准则,搜索准则的目的是为了帮助我们确定学习率,还有其他的一些准则,如Wolfe准则以及精确线搜索等。在利用Armijo搜索准则时并不是都满足上述的充要条件,此时可以对DFP校正公式做些许改变:
DFP拟牛顿法的算法流程如下:
1. 给定参数 δ∈(0,1),σ∈(0,0.5) ,初始化点 x0∈Rn ,终止误差 0≤ϵ≪1 ,初始化对称正定阵 H0 ,通常取为 G(xo)−1 或单位阵 In ;令 k=0 。
2. 计算 gk=∇f(xk) ,若 ∥gk∥≪ϵ ,终止,输出 xk 作为近似极小点。
3. 计算搜索方向 : dk=−Hkgk .
4. 设 mk 是满足下列不等式的最小非负整数m:
令 αk=δmk,xk+1=xk+αkdk .
5. 由校正公式确定 Hk+1
6. 令 k=k+1 ,转向步骤“2”
代码:
dfp.py
#coding:UTF-8
'''
Created on 2017年4月25日
@author: zhangdapeng
'''
from numpy import *
from function import *
def dfp(fun, gfun, x0):
result = []
maxk = 500
delta = 0.55
sigma = 0.4
m = shape(x0)[0]
Hk = eye(m)
k = 0
epsilon=1e-10
while (k < maxk):
gk = mat(gfun(x0))#计算梯度
if linalg.norm(gk,1)<epsilon:
break
dk = -mat(Hk)*gk
m = 0
mk = 0
while (m < 20):
newf = fun(x0 + delta ** m * dk)
oldf = fun(x0)
if (newf < oldf + sigma * (delta ** m) * (gk.T * dk)[0,0]):
mk = m
break
m = m + 1
#DFP校正
x = x0 + delta ** mk * dk
sk = x - x0
yk = gfun(x) - gk
if (sk.T * yk > 0):
Hk = Hk - (Hk * yk * yk.T * Hk) / (yk.T * Hk * yk) + (sk * sk.T) / (sk.T * yk)
k = k + 1
x0 = x
result.append(fun(x0))
return result
function.py
#coding:UTF-8
'''
Created on 2017年4月24日
@author: zhangdapeng
'''
from numpy import *
#fun 原始函数
def fun(x):
return 100 * (x[0,0] ** 2 - x[1,0]) ** 2 + (x[0,0] - 1) ** 2
#对x1,x2求导后的函数
def gfun(x):
result = zeros((2, 1))
# 对x1求导
result[0, 0] = 400 * x[0,0] * (x[0,0] ** 2 - x[1,0]) + 2 * (x[0,0] - 1)
result[1, 0] = -200 * (x[0,0] ** 2 - x[1,0]) #对x2求导
return result
testDFP.py
#coding:UTF-8
'''
Created on 2017年4月25日
@author: zhangdapeng
'''
from dfp import *
import matplotlib.pyplot as plt
x0 = mat([[-1.2], [1]])
result = dfp(fun, gfun, x0)
print(result[-1])
n = len(result)
ax = plt.figure().add_subplot(111)
x = arange(0, n, 1)
y = result
ax.plot(x,y)
plt.show()
输出结果:
1.54074395551e-28
输出图片:
http://blog.csdn.net/google19890102/article/details/45848439
http://blog.csdn.net/u012102306/article/details/50534086
http://www.codelast.com/%E5%8E%9F%E5%88%9B%E6%8B%9F%E7%89%9B%E9%A1%BF%E6%B3%95quasi-newton%EF%BC%8Cdfp%E7%AE%97%E6%B3%95davidon-fletcher-powell%EF%BC%8C%E5%8F%8Abfgs%E7%AE%97%E6%B3%95broyden-fletcher-goldfarb-shanno/