非线性优化之牛顿(梯度)下降法、高斯牛顿法、LM下降法

本质都是基于梯度下降法。
牛顿法: 依赖于Hessen矩阵非奇异,收敛较快
高斯 牛顿法:依赖二阶项的jacobian 解决了Hessen非奇异的问题,收敛相对慢
LM下降法:表现是使用一个因子拟合牛顿和高斯牛顿法

#coding=utf-8
from numpy import *
import sympy

def Hessen(f,x,x_value):
        #行 列表示Hesse矩阵
    num=len(x)
    lis2=mat([[1.0 for i in range(num)] for i in range(num)],dtype=float64)
        for i in range(num):
        for j in range(i,num):
            f1=sympy.diff(f,x[i],1)
            f2=sympy.diff(f1,x[j],1)
            value= f2.subs(x_value)
            lis2[i,j]=value
    return lis2


def Jacobian(f,x,x_value):
    num=len(x)
    lis1=mat([1.0 for i in range(num)])
    #print lis1
    for i in range(num):
        s2=sympy.diff(f,x[i],1)
        value= s2.subs(x_value)
        #print value
        lis1[0,i] =value
        #print lis1[0,i]
    return lis1.T

def handle(n): 
    x=[1 for i in range(n)]
    for i in range(n):
        str1='x['+str(i)+']'
        x[i] = sympy.Symbol(str1)
    return x

def Newton(f,x_value,maxIter):
    num=len(x_value.keys())
    x=handle(num)
    #求逆运算的问题
    error=f.subs(x_value)
    try:
        for i in range(maxIter):
            hessen=Hessen(f,x,x_value)
            I=mat(zeros((num,num)))
            #for q in range(num):
            #   I[q,q]=0.001
            jacobian=Jacobian(f,x,x_value)      
            delta=-1*dot((linalg.inv(hessen)+I),jacobian)
            #delta=dot(delta,error)
            #print jacobian,hessen,delta        
            for j in range(num):
                x_value[x[j]]=x_value[x[j]]+delta[j,0]
            error=f.subs(x_value)
            print i,error
    except:
        print "gradient is vanish"
    return x_value,error


def GaussNewton(f,x_value,maxIter):
    num=len(x_value.keys())
    x=handle(num)
    #求逆运算的问题
    error=f.subs(x_value)
    try:
        for i in range(maxIter):
            jacobian=Jacobian(f,x,x_value)  
            J1=dot(jacobian.T,jacobian)
            #print J1   
            J2=-1.0*dot(linalg.inv(J1),jacobian.T)
            delta=dot(J2,error).T   
            for j in range(num):
                x_value[x[j]]=x_value[x[j]]+delta[j,0]
            error=f.subs(x_value)
            print i,error
    except:
        pass
    return x_value,error



def LM(f,x_value,maxIter):
    num=len(x_value.keys())
    x=handle(num)
    #求逆运算的问题
    #last_value=f.subs(x_value)
    error=f.subs(x_value)
    lr=0.000001
    for i in range(maxIter):
        jacobian=Jacobian(f,x,x_value)  
        J1=dot(jacobian.T,jacobian)
        #print jacobian

        I=mat(zeros((len(J1),len(J1))))
        for q in range(len(J1)):
            I[q,q]=lr

        J1=J1+I
        J2=-1.0*dot(linalg.inv(J1),jacobian.T)
        delta=dot(J2,error).T

        for j in range(num):
            x_value[x[j]]=x_value[x[j]]+delta[j,0]
        if(f.subs(x_value)>=error):
            lr=lr*5
        else:
            lr=0.000001
        error=f.subs(x_value)
        print i,error
    return x_value,error




x=handle(2)
# sin cos need  like : sympy.sin()
f=(3-x[0])**2+(7-x[1])**2

x_value={x[0]:-1.5,x[1]:0.5};
maxIter=100

lis1=Jacobian(f,x,x_value)
#print lis1

lis2=Hessen(f,x,x_value)
#print lis2

#限制因素 非奇异矩阵
#Newton(f,x_value,100)

#GaussNewton(f,x_value,100)

#LM(f,x_value,100)



















  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LM算法,全称为Levenberg-Marquard算法,它可用于解决非线性最小二乘问题,多用于曲线拟合等场合。 LM算法的实现并不算难,它的关键是用模型函数 f 对待估参数向量 p 在其邻域内做线性近似,忽略掉二阶以上的导数项,从而转化为线性最小二乘问题,它具有收敛速度快等优点。LM算法属于一种“信赖域”——所谓的信赖域,此处稍微解释一下:在最优化算法中,都是要求一个函数的极小值,每一步迭代中,都要求目标函数值是下降的,而信赖域,顾名思义,就是从初始点开始,先假设一个可以信赖的最大位移 s ,然后在以当前点为中心,以 s 为半径的区域内,通过寻找目标函数的一个近似函数(二次的)的最优点,来求解得到真正的位移。在得到了位移之后,再计算目标函数值,如果其使目标函数值的下降满足了一定条件,那么就说明这个位移是可靠的,则继续按此规则迭代计算下去;如果其不能使目标函数值的下降满足一定的条件,则应减小信赖域的范围,再重新求解。 事实上,你从所有可以找到的资料里看到的LM算法的说明,都可以找到类似于“如果目标函数值增大,则调整某系数再继续求解;如果目标函数值减小,则调整某系数再继续求解”的迭代过程,这种过程与上面所说的信赖域是非常相似的,所以说LM算法是一种信赖域
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值