L-BFGS算法/Broyden族/BFGS算法/阻尼牛顿法的Python实现代码

下面定义了三个Python语言编写的函数:函数表达式fun,梯度向量gfun,和海森矩阵hess。这三个表达式在后面各个算法的实现中会用到。

# 函数表达式fun
fun = lambda x:100*(x[0]**2-x[1])**2 + (x[0]-1)**2# 梯度向量 gfun
gfun = lambda x:np.array([400*x[0]*(x[0]**2-x[1])+2*(x[0]-1), -200*(x[0]**2-x[1])])# 海森矩阵 hess
hess = lambda x:np.array([[1200*x[0]**2-400*x[1]+2, -400*x[0]],[-400*x[0],200]])

最速下降法的Python实现。

def gradient(fun,gfun,x0):#最速下降法求解无约束问题# x0是初始点,fun和gfun分别是目标函数和梯度maxk = 5000rho = 0.5sigma = 0.4k = 0epsilon = 1e-5while k<maxk:gk = gfun(x0)dk = -gkif np.linalg.norm(dk) < epsilon:breakm = 0mk = 0while m< 20:if fun(x0+rho**m*dk) < fun(x0) + sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1x0 += rho**mk*dkk += 1return x0,fun(x0),k

4.牛顿法
牛顿法的基本思想是用迭代点xkxk处的一阶导数(梯度gkgk)和二阶倒数(海森矩阵GkGk)对目标函数进行二次函数近似,然后把二次模型的极小点作为新的迭代点。

牛顿法推导

函数f(x)f(x)在xkxk处的泰勒展开式的前三项得
T(f,xk,3)=fk+gTk(x−xk)+12(x−xk)TGk(x−xk)
T(f,xk,3)=fk+gkT(x−xk)+12(x−xk)TGk(x−xk)

则其稳定点
∇T=gk+Gk(x−xk)=0
∇T=gk+Gk(x−xk)=0

若 GkGk非奇异,那么解上面的线性方程(标记其解为 xk+1xk+1)即得到牛顿法的迭代公式
xk+1=xk−G−1kgk
xk+1=xk−Gk−1gk

即优化方向为 dk=−G−1kgkdk=−Gk−1gk
求稳定点是用到了以下公式:

考虑y=xTAxy=xTAx,根据矩阵求导法则,有
dydx=Ax+ATxd2ydx2=A+AT
dydx=Ax+ATxd2ydx2=A+AT
注意实际中dkdk的是通过求解线性方程组Gkd=−gkGkd=−gk获得的。

阻尼牛顿法及其Python实现
阻尼牛顿法采用了牛顿法的思想,唯一的差别是阻尼牛顿法并不直接采用xk+1=xk+dkxk+1=xk+dk,而是用线搜索技术获得合适的步长因子αkαk,用公式xk+1=xk+δmdkxk+1=xk+δmdk计算xk+1xk+1。

阻尼牛顿法的算法描述:

step 1: 给定终止误差0≤ϵ≪1,δ∈(0,1),σ∈(0,0.5)0≤ϵ≪1,δ∈(0,1),σ∈(0,0.5). 初始点x0∈Rnx0∈Rn. 令k←0k←0
step 2: 计算gk=∇f(xk)gk=∇f(xk). 若||gk||≤ϵ||gk||≤ϵ,停止迭代,输出x∗≈xkx∗≈xk
step 3: 计算Gk=∇2f(xk)Gk=∇2f(xk),并求解线性方程组得到解dkdk,
Gkd=−gk
Gkd=−gk

step 4: 记 mkmk是满足下列不等式的最小非负整数 mm.
f(xk+βmdk)≤f(xk)+δβmgTkdk
f(xk+βmdk)≤f(xk)+δβmgkTdk

step 5: 令 αk=δmk,xk+1=xk+αkdk,k←k+1αk=δmk,xk+1=xk+αkdk,k←k+1,转 step 2
阻尼牛顿法的Python实现:

def dampnm(fun,gfun,hess,x0):# 用阻尼牛顿法求解无约束问题#x0是初始点,fun,gfun和hess分别是目标函数值,梯度,海森矩阵的函数maxk = 500rho = 0.55sigma = 0.4k = 0epsilon = 1e-5while k < maxk:gk = gfun(x0)Gk = hess(x0)dk = -1.0*np.linalg.solve(Gk,gk)if np.linalg.norm(dk) < epsilon:breakm = 0mk = 0while m < 20:if fun(x0+rho**m*dk) < fun(x0) + sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1x0 += rho**mk*dkk += 1return x0,fun(x0),k

性能展示

作图代码:

iters = []
for i in xrange(np.shape(data)[0]):rt = dampnm(fun,gfun,hess,data[i])if rt[2] <=200:iters.append(rt[2])if i%100 == 0:print i,rt[2]plt.hist(iters,bins=50)
plt.title(u'阻尼牛顿法迭代次数分布',{'fontname':'STFangsong','fontsize':18})
plt.xlabel(u'迭代次数',{'fontname':'STFangsong','fontsize':18})
plt.ylabel(u'频率分布',{'fontname':'STFangsong','fontsize':18})


修正牛顿法法及其Python实现
牛顿法要求目标函数的海森矩阵G(x)=∇2f(x)G(x)=∇2f(x)在每个迭代点xkxk处是正定的,否则难以保证牛顿方向dk=−G−1kgkdk=−Gk−1gk是ff在xkxk处的下降方向。为克服这一缺陷,需要对牛顿法进行修正。
下面介绍两种修正方法,分别是“牛顿-最速下降混合算法”和“修正牛顿法”。
牛顿-最速下降混合算法
该方法将牛顿法和最速下降法结合起来,基本思想是:当海森矩阵正定时,采用牛顿法确定的优化方向作为搜索方向;否则,即海森矩阵为非正定矩阵时,则采用负梯度方向作为搜索方向。

修正牛顿法
引入阻尼因子μk≥0μk≥0,即在每一迭代步适当选取参数μkμk,使得矩阵Ak=Gk+μkIAk=Gk+μkI正定,用AkAk代替GkGk来求解dkdk。

算法描述:

step 1: 给定终止误差0≤ϵ≪1,δ∈(0,1),σ∈(0,0.5)0≤ϵ≪1,δ∈(0,1),σ∈(0,0.5). 初始点x0∈Rnx0∈Rn. 令k←0k←0
step 2: 计算gk=∇f(xk)gk=∇f(xk),μk=||gk||1+τμk=||gk||1+τ. 若||gk||≤ϵ||gk||≤ϵ,停止迭代,输出x∗≈xkx∗≈xk
step 3: 计算Gk=∇2f(xk)Gk=∇2f(xk),并求解线性方程组得到解dkdk,
(Gk+μkI)d=−gk
(Gk+μkI)d=−gk

step 4: 记 mkmk是满足下列不等式的最小非负整数 mm.
f(xk+βmdk)≤f(xk)+δβmgTkdk
f(xk+βmdk)≤f(xk)+δβmgkTdk

step 5: 令 αk=δmk,xk+1=xk+αkdk,k←k+1αk=δmk,xk+1=xk+αkdk,k←k+1,转 step 2
修正牛顿法的Python实现代码:

def revisenm(fun,gfun,hess,x0):# 用修正牛顿法求解无约束问题#x0是初始点,fun,gfun和hess分别是目标函数值,梯度,海森矩阵的函数maxk = 1e5n = np.shape(x0)[0]rho = 0.55sigma = 0.4tau = 0.0k = 0epsilon = 1e-5while k < maxk:gk = gfun(x0)      if  np.linalg.norm(gk) < epsilon:breakmuk = np.power(np.linalg.norm(gk),1+tau)Gk = hess(x0)Ak = Gk + muk*np.eye(n)dk = -1.0*np.linalg.solve(Ak,gk)m = 0mk = 0while m < 20:if fun(x0+rho**m*dk) < fun(x0) + sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1x0 += rho**mk*dkk += 1return x0,fun(x0),k

5.拟牛顿法
牛顿法的优点是具有二阶收敛速度,缺点是:

但当海森矩阵G(xk)=∇2f(x)G(xk)=∇2f(x) 不正定时,不能保证所产生的方向是目标函数在xkxk处的下降方向。
特别地,当G(xk)G(xk)奇异时,算法就无法继续进行下去。尽管修正牛顿法可以克服这一缺陷,但修正参数的取值很难把握,过大或过小都会影响到收敛速度。
牛顿法的每一步迭代都需要目标函数的海森矩阵G(xk)G(xk),对于大规模问题其计算量是惊人的。
拟牛顿法的基本思想是用海森矩阵GkGk的某个近似矩阵BkBk取代GkGk. BkBk通常具有下面三个特点:

在某种意义下有Bk≈GkBk≈Gk ,使得相应的算法产生的方向近似于牛顿方向,确保算法具有较快的收敛速度。
对所有的kk,BkBk是正定的,从而使得算法所产生的方向是函数ff在xkxk处下降方向。
矩阵BkBk更新规则比较简单
设 f:Rn→Rf:Rn→R在开集D⊂RnD⊂Rn上二次连续可微,那么ff在xk+1xk+1处的二次近似模型为:
f(x)≈f(xk+1)+gTk+1(x−xk+1)+12(x−xk+1)TGk+1(x−xk+1)
f(x)≈f(xk+1)+gk+1T(x−xk+1)+12(x−xk+1)TGk+1(x−xk+1)
对上式求导得
g(x)≈gk+1+Gk+1(x−xk+1)
g(x)≈gk+1+Gk+1(x−xk+1)

令 x=xkx=xk,位移 sk=xk+1−xksk=xk+1−xk,梯度差 yk=gk+1−gkyk=gk+1−gk,则有
Gk+1sk≈yk
Gk+1sk≈yk
.
因此,拟牛顿法中近似矩阵BkBk要满足关系式
Bk+1sk=yk
Bk+1sk=yk

令 Hk+1=B−1k+1Hk+1=Bk+1−1,得到拟牛顿法的另一形式
Hk+1yk=sk
Hk+1yk=sk

其中 Hk+1Hk+1为海森矩阵逆矩阵的近似。上面两个公式称为 拟牛顿方程。
搜索方向由 dk=−Hkgkdk=−Hkgk或 Bkdk=−gkBkdk=−gk确定。根据近似矩阵的第三个特点,有
Bk+1=Bk+Ek,Hk+1=Hk+Dk
Bk+1=Bk+Ek,Hk+1=Hk+Dk

其中 Ek,DkEk,Dk为秩1或秩2矩阵。该公式称为 校正规则。
通常将上面的三个式子(拟牛顿方程和校正规则)所确立的方法称为拟牛顿法。从下面的拟牛顿法的几个变种可以看出,不同的拟牛顿法的主要区别在于更新公式的不同。
DFP算法及其Python实现
DFP算法的校正公式如下:
Hk+1=Hk−HkykyTkHkyTkHkyk+sksTksTkyk
Hk+1=Hk−HkykykTHkykTHkyk+skskTskTyk
注意公式中的两个分数结构,分母yTkHkykykTHkyk和sTkykskTyk是标量,分子HkykyTkHkHkykykTHk和sksTkskskT是与HkHk同型的矩阵,而且都是对称矩阵。若HkHk正定,且sTkyk>0skTyk>0,则Hk+1Hk+1也正定。

当采用精确线搜索时,矩阵序列HkHk的正定新条件sTkyk>0skTyk>0可以被满足。但对于ArmijoArmijo搜索准则来说,不能满足这一条件,需要做如下修正:
Hk+1=⎧⎩⎨HkHk−HkykyTkHkyTkHkyk+sksTksTkyksTkyk≤0sTkyk>0⎫⎭⎬
Hk+1={HkskTyk≤0Hk−HkykykTHkykTHkyk+skskTskTykskTyk>0}
DFP算法描述:

step 1: 给定参数δ∈(0,1),σ∈(0,0.5)δ∈(0,1),σ∈(0,0.5),初始点x0∈Rx0∈R,终止误差0≤ϵ≪10≤ϵ≪1.初始对称正定矩阵H0H0(通常取为G(x0)−1G(x0)−1或单位矩阵InIn).令k←0k←0
step 2: 计算gk=∇f(xk)gk=∇f(xk). 若||gk||≤ϵ||gk||≤ϵ,停止迭代,输出x∗≈xkx∗≈xk
step 3: 计算搜索方向
dk=−Hkgk
dk=−Hkgk

step 4: 记 mkmk是满足下列不等式的最小非负整数 mm.
f(xk+βmdk)≤f(xk)+δβmgTkdk
f(xk+βmdk)≤f(xk)+δβmgkTdk
令 αk=δmk,xk+1=xk+αkdkαk=δmk,xk+1=xk+αkdk
step 5: 由校正公式确定 Hk+1Hk+1
step 6: k←k+1k←k+1,转 step 2
DFP算法的代码实现

def dfp(fun,gfun,hess,x0):#功能:用DFP族算法求解无约束问题:min fun(x)#输入:x0是初始点,fun,gfun分别是目标函数和梯度#输出:x,val分别是近似最优点和最优解,k是迭代次数maxk = 1e5rho = 0.55sigma = 0.4epsilon = 1e-5k = 0n = np.shape(x0)[0]#海森矩阵可以初始化为单位矩阵Hk = np.linalg.inv(hess(x0)) #或者单位矩阵np.eye(n)while k < maxk :gk = gfun(x0)if np.linalg.norm(gk) < epsilon:breakdk = -1.0*np.dot(Hk,gk)m=0;mk=0while m < 20: # 用Armijo搜索求步长if fun(x0+rho**m*dk) < fun(x0)+sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1#print mk#DFP校正x = x0 + rho**mk*dksk = x - x0yk = gfun(x) - gk   if np.dot(sk,yk) > 0:Hy = np.dot(Hk,yk)print Hysy = np.dot(sk,yk) #向量的点积yHy = np.dot(np.dot(yk,Hk),yk) # yHy是标量#表达式Hy.reshape((n,1))*Hy 中Hy是向量,生成矩阵Hk = Hk - 1.0*Hy.reshape((n,1))*Hy/yHy + 1.0*sk.reshape((n,1))*sk/syk += 1x0 = xreturn x0,fun(x0),k#分别是最优点坐标,最优值,迭代次数


由以上代码可知,拟牛顿法只需要在迭代开始前计算一次海森矩阵,更一般的,根本就不计算海森矩阵,而是初始化为单位矩阵,在每次迭代过程中是不需按传统方法(二阶导数)计算海森矩阵的。

实际性能

相关代码:

n = 50
x = y = np.linspace(-10,10,n)
xx,yy = np.meshgrid(x,y)
data = [[xx[i][j],yy[i][j]] for i in range(n) for j in range(n)]
iters = []
for i in xrange(np.shape(data)[0]):rt = dfp(fun,gfun,hess,np.array(data[i]))if rt[2] <=200: # 提出迭代次数过大的iters.append(rt[2])if i%100 == 0:print i,rt[2]plt.hist(iters,bins=50)
plt.title(u'DFP迭代次数分布',{'fontname':'STFangsong','fontsize':18})
plt.xlabel(u'迭代次数',{'fontname':'STFangsong','fontsize':18})
plt.ylabel(u'频率分布',{'fontname':'STFangsong','fontsize':18})


BFGS算法及其Python实现
BFGS算法与DFP步骤基本相同,区别在于更新公式的差异
Bk+1=⎧⎩⎨BkBk−BkykyTkBkyTkBkyk+sksTksTkyksTkyk≤0sTkyk>0⎫⎭⎬
Bk+1={BkskTyk≤0Bk−BkykykTBkykTBkyk+skskTskTykskTyk>0}
BFGS算法的Python实现

def bfgs(fun,gfun,hess,x0):#功能:用BFGS族算法求解无约束问题:min fun(x)#输入:x0是初始点,fun,gfun分别是目标函数和梯度#输出:x,val分别是近似最优点和最优解,k是迭代次数  maxk = 1e5rho = 0.55sigma = 0.4epsilon = 1e-5k = 0n = np.shape(x0)[0]#海森矩阵可以初始化为单位矩阵Bk = eye(n)#np.linalg.inv(hess(x0)) #或者单位矩阵np.eye(n)while k < maxk:gk = gfun(x0)if np.linalg.norm(gk) < epsilon:breakdk = -1.0*np.linalg.solve(Bk,gk)m = 0mk = 0while m < 20: # 用Armijo搜索求步长if fun(x0+rho**m*dk) < fun(x0)+sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1#BFGS校正x = x0 + rho**mk*dksk = x - x0yk = 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/ysk += 1x0 = xreturn x0,fun(x0),k#分别是最优点坐标,最优值,迭代次数 


实际性能

相关代码:

iters = []
for i in xrange(np.shape(data)[0]):rt = bfgs(fun,gfun,hess,np.array(data[i]))if rt[2] <=200:iters.append(rt[2])if i%100 == 0:print i,rt[2]plt.hist(iters,bins=50)
plt.title(u'BFGS迭代次数分布',{'fontname':'STFangsong','fontsize':18})
plt.xlabel(u'迭代次数',{'fontname':'STFangsong','fontsize':18})
plt.ylabel(u'频率分布',{'fontname':'STFangsong','fontsize':18})


Broyden族算法及其Python实现
之前的BFGS和DFP校正都是由ykyk和BkskBksk(或 sksk和HkykHkyk)组成的秩2矩阵。而Broyden族算法采用了BFGS和DFP校正公式的凸组合,如下:
Hϕk+1=ϕkHBFGSk+1+(1−ϕk)HDFPk+1=Hk−HkykyTkHkyTkHkyk+sksTksTkyk+ϕkvkvTk
Hk+1ϕ=ϕkHk+1BFGS+(1−ϕk)Hk+1DFP=Hk−HkykykTHkykTHkyk+skskTskTyk+ϕkvkvkT

其中 ϕk∈[0,1]ϕk∈[0,1], vkvk由下式定义:
vk=yTkHkyk−−−−−−√(skyTksk−HkykyTkHkyk)
vk=ykTHkyk(skykTsk−HkykykTHkyk)
Broyden族算法Python实现

def broyden(fun,gfun,hess,x0):#功能:用Broyden族算法求解无约束问题:min fun(x)#输入:x0是初始点,fun,gfun分别是目标函数和梯度#输出:x,val分别是近似最优点和最优解,k是迭代次数x0 = np.array(x0)maxk = 1e5rho = 0.55;sigma = 0.4;epsilon = 1e-5phi = 0.5;k=0;n = np.shape(x0)[0]Hk = np.linalg.inv(hess(x0))while k<maxk :gk = gfun(x0)if np.linalg.norm(gk) < epsilon:breakdk = -1*np.dot(Hk,gk)m=0;mk=0while m < 20: # 用Armijo搜索求步长if fun(x0+rho**m*dk) < fun(x0)+sigma*rho**m*np.dot(gk,dk):mk = mbreakm += 1#Broyden族校正x = x0 + rho**mk*dksk = x - x0yk = gfun(x) - gkHy = np.dot(Hk,yk)sy = np.dot(sk,yk)yHy = np.dot(np.dot(yk,Hk),yk)if(sy < 0.2 *yHy):theta = 0.8*yHy/(yHy-sy)sk = theta*sk + (1-theta)*Hysy = 0.2*yHyvk = np.sqrt(yHy)*(sk/sy-Hy/yHy)Hk = Hk - Hy.reshape((n,1))*Hy/yHy +sk.reshape((n,1))*sk/sy + phi*vk.reshape((n,1))*vkk += 1x0 = xreturn x0,fun(x0),k #分别是最优点坐标,最优值,迭代次数


实际性能

相关代码:

n = 50
x = y = np.linspace(-10,10,n)
xx,yy = np.meshgrid(x,y)
data = [[xx[i][j],yy[i][j]] for i in range(n) for j in range(n)]iters = []
for i in xrange(np.shape(data)[0]):rt = lbfgs(fun,gfun,data[i])if rt[2] <=1000:iters.append(rt[2])if i%100 == 0:print i,rt[2]plt.hist(iters,bins=100)
plt.title(u'L-BFGS法迭代次数分布',{'fontname':'STFangsong','fontsize':18})
plt.xlabel(u'迭代次数',{'fontname':'STFangsong','fontsize':18})
plt.ylabel(u'频率分布',{'fontname':'STFangsong','fontsize':18})


L-BFGS算法及其Python实现
拟牛顿法(如BFGS算法)需要计算和存储海森矩阵,其空间复杂度是n2n2,当nn很大时,其需要的内存量是非常大的。为了解决该内存问题,有限内存BFGS(即传说中的L-BFGS算法)横空出世。

基本BFGS算法的校正公式可以改写成
Hk+1=(I−skyTksTkyk)Hk(I−yksTksTkyk)+sksTksTkyk
Hk+1=(I−skykTskTyk)Hk(I−ykskTskTyk)+skskTskTyk

记ρk=1/sTkykρk=1/skTyk,以及Vk=(I−ρkyksTk)Vk=(I−ρkykskT),则上式可以写成
Hk+1=VTkHkVk+ρksksTk
Hk+1=VkTHkVk+ρkskskT
给定一个初始矩阵H0H0(其取值后面有提到),则由上式的递推关系可以得到

H1=VT0H0V0+ρ0s0sT0
H1=V0TH0V0+ρ0s0s0T
H2=VT1H1V1+ρ1s1sT1=VT1(VT0H0V0+ρ0s0sT0)V1+ρ1s1sT1=VT1VT0H0V0V1+VT1ρ0s0sT0V1+ρ1s1sT1
H2=V1TH1V1+ρ1s1s1T=V1T(V0TH0V0+ρ0s0s0T)V1+ρ1s1s1T=V1TV0TH0V0V1+V1Tρ0s0s0TV1+ρ1s1s1T
⋯⋯⋯
⋯⋯⋯

更一般的,我们有
Hm+1=(VTKVTm−1⋯VT1VT0)H0(V0V1⋯Vm−1Vk)+(VTmVTm−1⋯VT2VT1)ρ0s0sT0(V1V2⋯Vm−1Vk)+(VTmVTm−1⋯VT3VT2)ρ1s1sT1(V2V3⋯Vm−1Vk)+⋯+(VTmVTm−1)ρm−2sm−2sTm−2(Vm−1Vk)VTkρm−1sm−1sTm−1Vk+ρmsmsTm
Hm+1=(VKTVm−1T⋯V1TV0T)H0(V0V1⋯Vm−1Vk)+(VmTVm−1T⋯V2TV1T)ρ0s0s0T(V1V2⋯Vm−1Vk)+(VmTVm−1T⋯V3TV2T)ρ1s1s1T(V2V3⋯Vm−1Vk)+⋯+(VmTVm−1T)ρm−2sm−2sm−2T(Vm−1Vk)VkTρm−1sm−1sm−1TVk+ρmsmsmT

在上式的右边中, H0H0是由我们设置的,其余变量可由保存的最近 mm次迭代所形成的向量序列,如位移向量序列{sk}{sk}和一阶导数差所形成的向量序列 {yk}{yk}获得。也就是说,可由最近 mm次迭代的信息计算当前的海森矩阵的近似矩阵。
补充几点:

H0=I⋅sTmymyTmymH0=I⋅smTymymTym,第一次迭代时,序列{ sksk}和{ ykyk}为空,则 H0=IH0=I
最初的若干次迭代, 序列{sksk}和{ykyk}的元素个数较小,会有n<mn<m,则将Hm+1Hm+1计算公式右边的mm换成nn即可。
随着迭代次数增加, 序列{sksk}和{ykyk}的元素个数增大,会有n>mn>m。由于我们只需要最近mm次迭代产生的序列元素,所以序列{sksk}和{ykyk}只需要保存最新的mm个元素即可,如果再有新的元素进入,则同时扔掉最旧的元素,以保证序列元素个数恒为mm。
这就是L-BFGS算法的思想。聪明的同学会问:你上面的公式不还是要计算海森矩阵的近似矩阵吗?那岂不是还是需要n2n2规模的内存?
其实在实际中是不计算该矩阵的, 而且不是采用上面的方法,而是直接得到HkgkHkgk,而搜索方向就是dk=−Hkgkdk=−Hkgk。下面给出了计算的函数twoloop(s,y,ρρ,gk)的伪代码,可知该函数内部的计算仅限于标量和向量,未出现矩阵。

函数参数s,ys,y即向量序列{sksk}和{ykyk},ρρ为元素序列{ρkρk},其元素ρk=1/sTkykρk=1/skTyk,gkgk是向量,为当前的一阶导数,输出为向量z=Hkgkz=Hkgk,即搜索方向的反方向
Functiontwoloop(s,y,ρ,gk)q=gkFori=k−1,k−2,…,k−mαi=ρisTiqq=q−αiyiHk=yTk−1sk−1/yTk−1yk−1z=HkqFori=k−m,k−m+1,…,k−1βi=ρiyTizz=z+si(αi−βi)Returnz
Functiontwoloop(s,y,ρ,gk)q=gkFori=k−1,k−2,…,k−mαi=ρisiTqq=q−αiyiHk=yk−1Tsk−1/yk−1Tyk−1z=HkqFori=k−m,k−m+1,…,k−1βi=ρiyiTzz=z+si(αi−βi)Returnz
给出L-BFGS的算法

可以看到其搜索方向dkdk是根据函数twolooptwoloop计算得到的。


L-BFGS算法Python实现

def twoloop(s, y, rho,gk):n = len(s) #向量序列的长度if np.shape(s)[0] >= 1:#h0是标量,而非矩阵h0 = 1.0*np.dot(s[-1],y[-1])/np.dot(y[-1],y[-1])else:h0 = 1a = empty((n,))q = gk.copy() for i in range(n - 1, -1, -1): a[i] = rho[i] * dot(s[i], q)q -= a[i] * y[i]z = h0*qfor i in range(n):b = rho[i] * dot(y[i], z)z += s[i] * (a[i] - b)return z   def lbfgs(fun,gfun,x0,m=5):# fun和gfun分别是目标函数及其一阶导数,x0是初值,m为储存的序列的大小maxk = 2000rou = 0.55sigma = 0.4epsilon = 1e-5k = 0n = np.shape(x0)[0] #自变量的维度s, y, rho = [], [], []while k < maxk :gk = gfun(x0)if np.linalg.norm(gk) < epsilon:breakdk = -1.0*twoloop(s, y, rho,gk)m0=0;mk=0while m0 < 20: # 用Armijo搜索求步长if fun(x0+rou**m0*dk) < fun(x0)+sigma*rou**m0*np.dot(gk,dk):mk = m0breakm0 += 1x = x0 + rou**mk*dksk = x - x0yk = gfun(x) - gk   if np.dot(sk,yk) > 0: #增加新的向量rho.append(1.0/np.dot(sk,yk))s.append(sk)y.append(yk)if np.shape(rho)[0] > m: #弃掉最旧向量rho.pop(0)s.pop(0)y.pop(0)k += 1x0 = xreturn x0,fun(x0),k#分别是最优点坐标,最优值,迭代次数

相关代码:

n = 50
x = y = np.linspace(-10,10,n)
xx,yy = np.meshgrid(x,y)
data = [[xx[i][j],yy[i][j]] for i in range(n) for j in range(n)]iters = []
for i in xrange(np.shape(data)[0]):rt = lbfgs(fun,gfun,data[i])if rt[2] <=1000:iters.append(rt[2])if i%100 == 0:print i,rt[2]plt.hist(iters,bins=100)
plt.title(u'L-BFGS法迭代次数分布',{'fontname':'STFangsong','fontsize':18})
plt.xlabel(u'迭代次数',{'fontname':'STFangsong','fontsize':18})
plt.ylabel(u'频率分布',{'fontname':'STFangsong','fontsize':18})

如果对代码有疑问,欢迎添加微信 : 18565453898

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/546985.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

公网访问阿里云数据库MongoDB——填坑笔记

业务情景 两台服务器&#xff0c;一台阿里云ECS云服务器&#xff08;专用网络&#xff09;&#xff0c;另一台是阿里云数据库MongoDB&#xff0c;处于安全考虑MongoDB是不运行外网连接的&#xff0c;那接下来就看怎么实现公网访问。 看到上面红色的网络类型描述&#xff0c;有…

华为S5700交换机开启telnet远程登陆配置(推荐)

实验目标: 电脑PC1经过S3700交换机,telnet远程登录到S5700交换机。 连接拓扑图如下:(测试时用实物测试) 一、配置S5700交换机。 1.交换机开启Telnet服务 <Huawei>system-view Enter system view, return user view with Ctrl+Z. [Huawei]sysname LSW1 [LSW1]

2021最新Python量化A股投资必赚策略

一、板块信息&#xff1a; 1、每隔30分钟后台自动采集一个开盘啦的板块信息&#xff08;9:15开始到15:00是股票开市时间&#xff0c;如果15点以后已经采集过数据&#xff0c;就不需要重复采集&#xff0c;避免频繁采集被网站屏蔽&#xff09;。按照codelist.txt列表&#xff0…

Ubuntu安装设置nginx和nohup常用操作

nginx安装 Ubuntu直接从常规源中安装 apt-get install nginx 安装的目录 配置文件&#xff1a;/etc/nginx/主程序文件&#xff1a;/usr/sbin/nginxWeb默认目录&#xff1a;/usr/share/nginx/http/日志目录&#xff1a;/var/log/nginx/ nginx常用命令 1、启动/停止nginx服务 1…

crontab环境变量

为什么80%的码农都做不了架构师&#xff1f;>>> 设置了一个crontab30 0 * * * cd /home/work/user/huangbx/research/getfeature/data/current; sh resample.sh &>/dev/null$sh resample.sh是可以运行的$head -5 resample.sh##对事实数据进行采样set -xg_da…

不同网段通过静态路由实现互通(强烈推荐)

实验拓扑图如下&#xff1a; 只贴出PC1到S5700链路的配置代码&#xff01; 一、华为交换机S5700配置 1.新建VLAN66 <Huawei>system-view Enter system view, return user view with CtrlZ. [Huawei]sysname LSW4 [LSW4]vlan 66 //新建管理VLAN [LSW4-vlan66]quit [L…

Hadoop 副本存储策略的源码修改和设置

Table of Contents BlockPlacementPolicyHadoop 提供的 BlockPlacementPolicy 实现BlockPlacementPolicyDefault 源码阅读 首先处理favoredNodes三副本选择再到具体的选择源码阅读的几个注意修改HDFS默认的副本放置机制RackAwareness 机架感知 大多数的叫法都是副本放置策略&a…

fabric.js和高级画板

本文介绍fabric.js框架使用&#xff0c;以及使用fabricjs打造一个高级画板程序. 高级画板功能介绍 全局绘制颜色选择护眼模式、网格模式切换自由绘制画箭头画直线画虚线画圆/椭圆/矩形/直角三角形/普通三角形/等边三角形文字输入图片展示及相关移动、缩放等操作删除功能 &am…

Python模块学习——tempfile

主要有以下几个函数&#xff1a; tempfile.TemporaryFile 如何你的应用程序需要一个临时文件来存储数据&#xff0c;但不需要同其他程序共享&#xff0c;那么用TemporaryFile函数创建临时文件是最好的选择。其他的应用程序是无法找到或打开这个文件的&#xff0c;因为它并没有…

不同网段通过静态路由实现互通,华为S5700交换机开启telnet远程指定IP登陆配置(强烈推荐)

首先,不同网段通过静态路由实现互通配置方法,参考不同网段通过静态路由实现互通 在以上基础上,还需要配置 一、配置S5700交换机。 1.交换机开启Telnet服务 <Huawei>system-view Enter system view, return user view with Ctrl+Z. [Huawei]sysname LSW4 [

如何系统学习python

前言 最早接触python的时候&#xff0c;他并没有现在这么火&#xff0c;我也没把他太当回事&#xff0c;那时候我对python的印象就是给运维人员使用的一门很古老的语言&#xff0c;显然随着tensorflow&#xff08;以下简称tf&#xff09;的兴起&#xff0c;python开始频繁的进入…

Centos7.x Hadoop 3.x HDFS 写入文件

操作目的 1、在Linux环境下 编写HDFS写文件程序的java文件 2、编译并打包HDFS的写程序 3、执行HDFS的写程序 环境、工具说明 1、先搭建一个 Hadoop 的基础集群环境 参考&#xff1a;Hadoop集群搭建 2、JDK版本&#xff1a;jdk1.8 安装配置过程 3、工具&#xff1a;xshell5 4、…

不同网段通过静态路由实现互通,华为S5700交换机开启SSH远程指定IP登陆配置(强烈推荐)

首先,不同网段通过静态路由实现互通配置方法,参考不同网段通过静态路由实现互通 在以上基础上,还需要配置 一、配置S5700交换机。 1.交换机开启stelnet服务 <Huawei>system-view Enter system view, return user view with Ctrl+Z. [Huawei]sysname LSW4 [

mysql线程缓存和表缓存

一.线程缓存1.thread_cache_size定义了线程缓冲中的数量.每个缓存中的线程通常消耗256kb内存2.Threads_cached,可以看到已经建立的线程二.表缓存(table_cache)1.表缓存有点以myisam为中心2.在mysql5.1中,这个变量被分为两部分.表缓存分为两个部分:一部分为打开表,一部分为定义表…

图片人脸检测——OpenCV版(二)

图片人脸检测 人脸检测使用到的技术是OpenCV&#xff0c;上一节已经介绍了OpenCV的环境安装&#xff0c;点击查看. 功能展示 识别一种图上的所有人的脸&#xff0c;并且标出人脸的位置&#xff0c;画出人眼以及嘴的位置&#xff0c;展示效果图如下&#xff1a; 多张脸识别效果图…

wordpress for sae建站全过程

为什么80%的码农都做不了架构师&#xff1f;>>> 文章链接 http://www.brighttj.com/wordpress/use-wordpress-for-sae/ 里面详细的介绍了整个博客网站搭建的过程。多捧场。 转载于:https://my.oschina.net/saitjr/blog/197592

Tesseract Ocr文字识别

Tesseract的OCR引擎最先由HP实验室于1985年开始研发&#xff0c;至1995年时已经成为OCR业内最准确的三款识别引擎之一。2005年&#xff0c;Tesseract由美国内华达州信息技术研究所获得&#xff0c;并求诸于Google对Tesseract进行改进、消除Bug、优化工作。Tesseract目前已作为开…

jenkins用ssh agent插件在pipeline里实现scp和远程执行命令

现在ssh agent的认证&#xff0c;已不支持明文用户密码&#xff0c;而只能用加密方式实现。 所以我先在jenknis和nginx服务器之后&#xff0c;实现ssh免密码rsa证书登陆。 私钥放jenkins&#xff0c;公钥放nginx。然后&#xff0c;将私钥拿出来&#xff0c;后面要写入jenkins…

QT5 获取窗口、系统屏幕大小尺寸信息,Qt 获取控件位置坐标,屏幕坐标,相对父窗体坐标

一、QT5 获取窗口大小尺寸信息 QT窗口尺寸&#xff0c;窗口大小和大小改变引起的事件 QResizeEvent。 //窗口左上角的位置(含边框)qDebug() << this->frameGeometry().x() << this->frameGeometry().y() << ;//1qDebug() << this->x() <…

nutch,hbase,zookeeper兼容性问题

nutch-2.1使用gora-0.2.1&#xff0c; gora-0.2.1使用hbase-0.90.4&#xff0c;hbase-0.90.4和hadoop-1.1.1不兼容&#xff0c;hbase-0.94.4和gora-0.2.1不兼容&#xff0c;hbase-0.92.2没问题。 由川哥的博客的这段话可以知道&#xff0c;nutch-2.1 hadoop 1.1.1 hbase-0.92.…