拟牛顿法python_优化算法推导&手写实现——牛顿法和拟牛顿法2

本文介绍了BFGS(Broyden-Fletcher-Goldfarb-Shanno)算法的推导过程及Python实现,用于优化模型参数。在BFGS中,通过矩阵B逼近海塞矩阵,利用Sherman-Morrison公式推导出矩阵B的逆矩阵迭代公式。文章还展示了BFGS算法与DFP算法的对比,指出BFGS在相同条件下迭代次数更少。
摘要由CSDN通过智能技术生成

小伙伴们,“五一节”快乐。节前我们讲到了牛顿法的推导,以及拟牛顿法中DFP算法的推导与Python手写实现。今天我们继续来讲讲拟牛顿法中的BFGS算法的推导和实现。

1、BFGS算法(Broyden-Fletcher-Goldfarb-Shanno)推导在DFP算法中,我们用矩阵

逼近海塞矩阵的逆矩阵

,相应的拟牛顿条件是:DFP算法的拟牛顿条件在BFGS算法中,我们用矩阵

逼近海塞矩阵

,相应的拟牛顿条件是:BFGS算法的拟牛顿条件同样地,我们假设:两边乘以

,可得:为满足上式要求,我们不妨令:求解矩阵P过程如下:求解矩阵Q过程如下:最终,BFGS算法中的迭代公式如下:到这里,我们已经能用矩阵B来逼近海塞矩阵H了,不过这并不是我们的最终目的,我们最终还是希望得到矩阵B的逆矩阵的迭代公式,因此我们接着用Sherman-Morrison公式进行推导。Sherman-Morrison公式推导过程省略,最后得到矩阵B的逆矩阵迭代公式如下:BFGS算法中逼近海塞矩阵逆矩阵的迭代公式

Python实现BFGS算法:

我们接着上次DFP算法来添加方法。

def train(self, X, y, n_iters=1000, learning_rate=0.01):

"""fit model"""

if X.ndim < 2:

raise ValueError("X must be 2D array-like!")

self.trainSet = X

self.label = y

if self.method.lower() == "gradient":

self._LogisticRegressionSelf__train_gradient(n_iters, learning_rate)

elif self.method.lower() == "newton":

self._LogisticRegressionSelf__train_newton(n_iters)

elif self.method.lower() == "dfp":

self.__train_dfp(n_iters, learning_rate)

elif self.method.lower() == "bfgs":

self.__train_bfgs(n_iters, learning_rate)

else:

raise ValueError("method value not found!")

return

在写算法主体前,我们同样先看下BFGS的简易优化过程:初始化参数W0,初始化替代矩阵Bk0,计算初始梯度Gk0,迭代次数k;

While ( k < n_iters ) and ( ||Gk0|| > e ):

1. 计算出W0需要优化的方向Pk = Bk*Gk0

2. 更新参数W1如下:

---- for n in N:

-------- 尝试用一维搜索方法改变Pk的学习率,

-------- 求得最小似然值,

-------- 求出W1和deltaW(W1 - W0)

3. 更新梯度Gk1,并求deltaG(Gk1 - Gk0)

4. 更新BK1,利用上述推导的BFGS的迭代公式

5. 重新赋值W0,Bk0,Gk0

6. k += 1end.

由此我们可以看到,我们可以直接复用DFP算法的内循环,而外循环也仅需改动下

的迭代方法。

#新增拟牛顿法-BFGS优化算法

def __train_bfgs(self, n_iters, learning_rate):

n_samples, n_features = self.trainSet.shape

X = self.trainSet

y = self.label

#合并w和b,在X尾部添加一列全是1的特征

X2 = np.hstack((X, np.ones((n_samples, 1))))

#将y转置变为(n_samples,1)的矩阵

Y = np.expand_dims(y, axis=1)

#初始化特征系数W,初始化替代对称矩阵

W = np.zeros((1, n_features+1))

Bk0 = np.eye(n_features+1)

#计算初始的预测值、似然值,并记录似然值

Ypreprob, LL0 = self.PVandLLV(X2, Y, W)

self.llList.append(LL0)

#根据初始的预测值计算初始梯度,并记录梯度的模长

Gk0 = self._LogisticRegressionSelf__calGradient(X2, Y, Ypreprob)

graLength = np.linalg.norm(Gk0)

self.graList.append(graLength)

#初始化迭代次数

k = 0

while (kself.tol):

#计算优化方向的值Pk=Gk0.Bk0

Pk = np.dot(Gk0, Bk0)

#一维搜索更新参数,并保存求得的最小似然值

W, deltaW, min_LLvalue, Ypreprob = self.__updateW(X2, Y, learning_rate, W, Pk)

self.llList.append(min_LLvalue)

#更新梯度Gk和deltaG,同时求得梯度的模长和更新前后的模长差值

Gk1 = self._LogisticRegressionSelf__calGradient(X2, Y, Ypreprob)

graLength = np.linalg.norm(Gk1)

self.graList.append(graLength)

deltaG = Gk1 - Gk0

Gk0 = Gk1

#更新替代矩阵Bk

temp = (np.eye(n_features+1)-np.dot(deltaW.T,deltaG)/np.dot(deltaW,deltaG.T))

Bk1 = np.dot(np.dot(temp, Bk0), temp.T) + np.dot(deltaW.T, deltaW)/np.dot(deltaW, deltaG.T)

Bk0 = Bk1

k += 1

self.n_iters = k

self.w = W.flatten()[:-1]

self.b = W.flatten()[-1]

Ypre = np.argmax(np.column_stack((1-Ypreprob,Ypreprob)), axis=1)

self.accurancy = sum(Ypre==y)/n_samples

print("第{}次停止迭代,梯度模长为{},似然值为{},准确率为{}".format(self.n_iters, self.graList[-1], self.llList[-1], self.accurancy))

print("w:{};\nb:{}".format(self.w, self.b))

return我们和DFP算法做个对比,先看DFP算法的结果:再看BFGS算法的结果:其实经过多次实验,我们可以发现,DFP和BFGS算法在似然值和梯度的下降曲线比较近似,但是在同样的停止条件下,BFGS的迭代次数更少一些。

以上就是拟牛顿法BFGS算法的全部内容,谢谢阅读。

全部代码可前往以下地址下载:https://github.com/shoucangjia1qu/ML_gzh/tree/master/LogisticRegression​github.com

往期回顾:

学无止境,欢迎关注笔者公众号,互相学习!嗷大豆的数据工厂

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值