目录
1.1BFGS公式推导
BFGS是可以认为是由DFP算法推导出来的,上篇文章有详细的推导:(拟牛顿法公式推导以及python代码实现(一))
目前BFGS被证明是最有效的拟牛顿优化方法。它的思想是根据我们已知的两个拟牛顿条件:
由上一篇文章,我们得到DFP的校正公式为:
这个是BFGS的 BK Hessian矩阵形式的,要想得到它的Hessian逆阵的形式,需要多次使用Sherman-Morrison公式,推导太麻烦,在此不细讲。
现不加证明给出BFGS的 Hk 形式:
1.2 python实现
由于 Bk+1 的公式较为简单,我们采用该校正公式进行实现有:
同样采用上一篇文章的优化问题 3.2,文章链接:拟牛顿法公式推导以及python代码实现(一)。
def bfgs(fun,gfun,hess,x0):
#功能:用BFGS族算法求解无约束问题:min fun(x) 优化的问题请参考文章开头给出的链接
#输入:x0是初始点,fun,gfun分别是目标函数和梯度,hess为Hessian矩阵
#输出:x,val分别是近似最优点和最优解,k是迭代次数
maxk = 1e5
rho = 0.55
sigma = 0.4
gama = 0.7
epsilon = 1e-5
k = 0
n = np.shape(x0)[0]
#海森矩阵可以初始化为单位矩阵
Bk = np.eye(n) #np.linalg.inv(hess(x0)) #或者单位矩阵np.eye(n)
while k < maxk:
gk = gfun(x0)
if np.linalg.norm(gk) < epsilon:
break
dk = -1.0*np.linalg.solve(Bk,gk)
m = 0
mk = 0
while m < 20: # 用Wolfe条件搜索求步长
gk1 = gfun(x0 + rho**m*dk)
if fun(x0+rho**m*dk) < fun(x0)+sigma*rho**m*np.dot(gk,dk) and np.dot(gk1.T, dk) >= gama*np.dot(gk.T,dk):
mk = m
break
m += 1
#BFGS校正
x = x0 + rho**mk*dk
print "第"+str(k)+"次的迭代结果为:"+str(x)
sk = x - x0
yk = gfun(x) - gk
if np.dot(sk,yk) > 0:
Bs = np.dot(Bk,sk)
ys = np.dot(yk,sk)
sBs = np.dot(np.dot(sk,Bk),sk)
Bk = Bk - 1.0*Bs.reshape((n,1))*Bs/sBs + 1.0*yk.reshape((n,1))*yk/ys
k += 1
x0 = x
return x0,fun(x0),k#分别是最优点坐标,最优值,迭代次数
x0 ,fun0 ,k = bfgs(fun,gfun,hess,np.array([3,3]))
print x0,fun0,k
使用Wolfe条件寻找步长 + BFGS的 Bk+1 形式校正,可得:
第0次的迭代结果为:[-7201. 1203.]
第1次的迭代结果为:[-3238.84711944 1221.61142361]
第2次的迭代结果为:[ -8.23623337e+04 1.30503639e+09]
第3次的迭代结果为:[ -3.36915508e+03 1.99855239e+07]
第4次的迭代结果为:[ -3.26209243e+03 3.56080380e+06]
-----
第3004次的迭代结果为:[ 1.00068614 1.00142718]
第3005次的迭代结果为:[ 0.99997941 0.99996238]
第3006次的迭代结果为:[ 0.99999746 0.99999526]
第3007次的迭代结果为:[ 1.00000001 1.00000001]
[ 1.00000001 1.00000001] 1.34694902629e-14 3008
迭代3008步才找到近似最优解
如果单独使用Armijo条件寻找步长的话:
第6298次的迭代结果为:[ 1.00031974 1.00067098]
第6299次的迭代结果为:[ 1.00001393 1.00002735]
第6300次的迭代结果为:[ 1.00000048 1.0000009 ]
第6301次的迭代结果为:[ 1. 1.]
[ 1. 1.] 3.15116026023e-16 6302
需要迭代6302步,但可以找到全局最优解[1. 1.]
1.1 L-BFGS的完整推导
拟牛顿法如BFGS需要计算并存储Hessian矩阵,其空间复杂度为 n2 ,当n很大的时候,需要的内存量相当大,为了解决这个问题,L-BFGS就出来了。
L-BFGS的完整推导有空再写了