基于二阶矩阵的优化问题(一)线搜索策略(附matlab代码)

非精确线搜索更新 X k + 1 X_{k+1} Xk+1

优化算法的问题在于如何从 X k X_k Xk更新到 X k + 1 X_{k+1} Xk+1、确定步长公式详见 基于二阶矩阵的优化问题(二)和判定迭代终止的条件(详见 于二阶矩阵的优化问题(三))是我们需要在不精确搜索中解决的问题。
我们有两种方法来解决这个问题:
1.线搜索策略
2.信任域策略

线搜索策略

我们选择一个下降方向来使得lost function慢慢迭代至最小值。

X k + 1 = X k + α k p k X_{k+1}=X_k+α_kp_k Xk+1=Xk+αkpk

这是 X k + 1 X_{k+1} Xk+1的更新公式,可以看到,我们需要知道其 α k α_k αk p k p_k pk的值才能进行迭代( α k α_k αk代表了步长、 p k p_k pk代表下降方向),第一种方法就是 p k p_k pk走一个最速下降方向(负梯度),而 α k α_k αk走一个极其猥琐的距离,但这种方法在函数比较诡异时效果较差(如rosenbrock函数),但在某些复杂问题时,我们还是使用最速下降来解决问题,详见 大规模的优化问题(一)

最速下降+牛顿法

让我们来列一下牛顿方向的式子:

f ( x k + p ) ≈ f k + p T ∇ f k + 1 2 p T ∇ 2 f k p f(x_k+p)\approx f_k+p^T\nabla f_k+\frac{1}{2}p^T\nabla^2f_kp f(xk+p)fk+pTfk+21pT2fkp

在这里,我们要假设这里的二次型( ∇ 2 f k \nabla^2 f_k 2fk)是正定的,这是函数的局部二次型构型就是碗状的,我们可以求出这里的pk(下降方向):

p K N = − ( ∇ 2 f k ) − 1 ∇ f k p^N_K=-(\nabla^2f_k)^{-1}\nabla f_k pKN=(2fk)1fk;

这边的 p K N p^N_K pKN就是这里的局部二次型的顶点,在牛顿法中,我们可以一步就走到这个点。
ok,这个问题的理论情况是这样的,但在实际问题中,我们不可能去求一个hessian矩阵的逆矩阵,所以,我们把 1 / ( ∇ 2 f k ) 1/(\nabla^2f_k) 1/(2fk)移到等式的左边,变成:

p K N ∗ ( ∇ 2 f k ) = − ∇ f k p^N_K*(\nabla^2f_k)=-\nabla f_k pKN(2fk)=fk

这个等式实际上就等于Ax=b的形式,这边我们只需要求解一个线性方程组即可。
以上为牛顿法的基础理论,下面看一下牛顿法的实现步骤:

Created with Raphaël 2.3.0 开始 最速下降 ▽fk<阈值 转到Newton yes no

可以看到,牛顿法的意义在于足够靠近真解时的快速收敛,我们先走几部最速下降法,使得足够靠近阈值,后再启动牛顿法,会有较好的效果,即保证了算法的效率,有保证了算法的鲁棒性。

下面是最速下降法+牛顿法matlab实现的代码:

function [x1] = min_hybrid(func, dfunc, d2func ,x, MAX_IT ,eps, threshold)
    err = 10.0;
    steps = 0;
    alpha = 1.0;
    //最速下降法
    while (err > threshold)//此处阈值需要调参
        f = func(x);
        g = dfunc(x);
        p = -g;
        step=step+1;
        alpha = backtracking(@func, x, f, g, p, 1e-4, 0.8, alpha * 2.0);
        x = x + alpha * p;
        if (steps > MAX_IT)
            break;
        end
        error = norm(g);
    end
    //牛顿法
    while (error > eps)
        f = func(x);
        g = dfunc(x);
        G = d2func(x);
        p = -G\g;
        x = x + p;
        step=step+1;
        if (steps > MAX_IT)
            break;
        end
        error = norm(g);
    end
	x1=x;
end

function alpha = backtracking(func, x, f, df, p, c, rho, alpha0)
    alpha = alpha0;
    while (func(x(1) + alpha * p(1), x(2) + alpha * p(2)) > f + c * alpha * df' * p)
        alpha = alpha * rho;
    end
end

其中func、gfunc和hess需要自行解析计算,func的接口只有x,gfunc和hess没有输入参数。(这边要注意,使用wolfe条件时,alpha可以恒取1)

启发

牛顿法实际上是在改进真解,用少量次数的迭代即可实现一阶方法上千次的迭代效果,首先系数矩阵必须要正定,否则牛顿法不能保证收敛。

修正牛顿法

牛顿法最大的问题在于,系数矩阵必须要正定,那么如果系数矩阵不正定,则 B k B_k Bk改成正定(modification),下面是修改系数矩阵的算法框架:

初值 x 0 x_0 x0
for k=0,1,2,…
        令 B k = ∇ 2 f k + E k B_k=\nabla^2 f_k+E_k Bk=2fk+Ek,其中 E k E_k Ek为修正项,使得 B k B_k Bk充分正定。
        求解 B k p k = − ∇ f k B_kp_k=-\nabla f_k Bkpk=fk
         x k + 1 = x k + α k p k x_{k+1}=x_k+α_kp_k xk+1=xk+αkpk(其中 α k α_k αk在wolfe条件时可以取1)
end

好了,现在我们需要解决四件事,就可以实现修正牛顿法的运用:
1.判定 ∇ 2 f k \nabla^2 f_k 2fk是否正定;
2.解方程组 B k p k = − ∇ f k B_kp_k=-\nabla f_k Bkpk=fk
3.如何构建 E k E_k Ek
4.如何使得 ∣ ∣ E k ∣ ∣ \vert\vert E_k\vert\vert Ek最小;

特征值修正(eigenvalue modification)
谱分解

首先我们先对对称矩阵 B k B_k Bk正交分解(householder等),得到正交阵Q,和对角阵V,然后就可以得到 B k B_k Bk的所有特征值,我们知道,正定矩阵所有的特征值都是充分大的正数,即 λ m i n > δ > > e p s > 0 λ_{min}>δ>>eps>0 λmin>δ>>eps>0,当出现负的特征值时,我们添加一个修正项 E k E_k Ek使得特征值大于等于δ。此时的 ∣ ∣ E k ∣ ∣ \vert\vert E_k\vert\vert Ek的Frobenius范数最小。
即用Matlab中的eig()函数求出特征值后,直接对特征值修改即可。

单位增量法

谱分解的问题在于,其真正改变的是特征值,所以对 B k B_k Bk的改动是比较的,当我们不希望 B k B_k Bk发生很大的变动时,我们就使用单位增量法。单位增量法直接对 B k B_k Bk添加一个修正项 E k I E_kI EkI,使得其正定。
首先,我们对 B k B_k Bk进行cholesky分解:

B k = L D L T B_k=LDL^T Bk=LDLT

L是对角线均为1的下三角阵,D为对角阵,若 B k B_k Bk不定,D的对角元 d i i d_{ii} dii会过大。
下面是单位增量法的Matlab代码:

function[L,D]=modification(A,delta,beta)
	if(norm(A-A')>eps
		return;
	end
	n=size(A,1);
	d=zero(n,1);
	L=zero(n);
	C=zero(n);
	theta=zeros(n,1);
	for j = 1:n
		C(j,j) = A(j,j)-sum(d(1:j-1)'.*L(j,1:j-1).^2);
		for i = j+1:n
			C(i,j) = A(i,j)-sum(d(1:j-1)'.*L(i,1:j-1).*L(j,1:j-1));
			absjj=abs(C(i,j));
			if theta < abs(C(i,j))
				theta = abs(C(i,j));
			end
		end
		d(j) = max([abs(C(j,j)), (theta/beta)^2, \delta]);
		for i = j+1:n
			L(i,j) = C(i,j)/d(j);
		end
		L(j,j) = 1.0;
	end
	D=diag(d);
end

单位增量法得到的 B k B_k Bk B k + E k B_k+E_k Bk+Ek在形式上很接近,但其特征值完全不同,所以两种方法各有优势,可根据情况自行选择。

拟牛顿法

如果你的数据维数过大或者无法承受计算二阶矩阵的消耗,这边也可以使用拟牛顿法来计算下降方向,当然拟牛顿法也有其缺陷,下面我们来分析一下。
首先我们介绍一下割线法,用弦的斜率近似代替目标函数的切线斜率,下面给出割线法的公式

x k + 1 = x k − f ( x k ) ∗ x k − 1 − x k f ( x k − 1 ) − f ( x k ) x_{k+1}=x_k-f(x_k)*\frac{x_{k-1}-x_k}{f(x_{k-1})-f(x_k)} xk+1=xkf(xk)f(xk1)f(xk)xk1xk

这在本质上是计算函数的数值微分,但这种方法在接近收敛时会出现数值不稳定的情况,当接近收敛时,舍入误差占比变大,数值会发生很大的起伏变化。
由此我们可以推导出拟牛顿法的公式

x k + 1 = x k − ∇ f ( x k ) ∗ x k − 1 − x k ∇ f ( x k − 1 ) − ∇ f ( x k ) x_{k+1}=x_k-\nabla f(x_k)*\frac{x_{k-1}-x_k}{\nabla f(x_{k-1})-\nabla f(x_k)} xk+1=xkf(xk)f(xk1)f(xk)xk1xk

这里不在需要计算其hessian矩阵,由于hessian矩阵是 n 2 n^2 n2级别的,拟牛顿法对于大规模问题来说是非常节约资源的方法

于是我们知道了

∇ 2 f ( x k ) ∗ ( x k + 1 − x k ) ≈ ∇ f x + 1 − ∇ f k \nabla ^2f(x_k)*(x_{k+1}-x_k)\approx\nabla f_{x+1}-\nabla f_k 2f(xk)(xk+1xk)fx+1fk

现在的情况与牛顿发不同, ∇ f ( x k ) \nabla f(x_k) f(xk)并不知道,这是一个不定方程组:

B k + 1 ∗ s k = y k B_{k+1}*s_k=y_k Bk+1sk=yk

这里的 B k + 1 B_{k+1} Bk+1 n 2 n^2 n2阶的矩阵,而我们只有n个方程,下面有SR1、BFGS等方法来求解 B k + 1 B_{k+1} Bk+1
详见 拟牛顿法的下降方向计算(一)
此时,局部二次型的 p K N p_K^N pKN方程变为

p K N = − ( B k ) − 1 ∇ f k p^N_K=-(B_k)^{-1}\nabla f_k pKN=(Bk)1fk;

这里还有一条路,就是去构建 ( B k ) − 1 (B_k)^{-1} (Bk)1,这时我们不需要再去求解线性方程组(这里设 H k = ( B k ) − 1 H_k=(B_k)^{-1} Hk=(Bk)1),这里 B k B_k Bk=I时,就是最速下降。

p k = − H k ∗ ∇ f k p_k=-H_k*\nabla f_k pk=Hkfk

这里有拟BFGS等方法来求解 H k H_k Hk,详见 拟牛顿法的下降方向计算(二)

github代码地址

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员毛师傅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值