牛顿法及梯度下降算法原理

一. 牛顿法原理:

(1)定义:

牛顿法一般指牛顿迭代法。牛顿迭代法(Newton’s method)又称为牛顿-拉夫逊(拉弗森)方法(Newton-Raphson method),它是牛顿在17世纪提出的一种在实数域和复数域上近似求解方程的方法。

(2)产生背景:

多数方程不存在求根公式,因此求精确根非常困难,甚至不可能,从而寻找方程的近似根就显得特别重要。方法使用函数 f(x) 的泰勒级数的前面几项来寻找方程 f(x)=0 的根。牛顿迭代法是求方程根的重要方法之一,其最大优点是在方程 **f(x)=0 **的单根附近具有平方收敛,而且该法还可以用来求方程的重根、复根,此时线性收敛,但是可通过一些方法变成超线性收敛。另外该方法广泛用于计算机编程中。

(3)公式:

1. 一元函数情况:

为了能让大家更好的理解推导过程的原理,首先考虑一元函数的情况。根据一元函数的泰勒展开公式,我们对目标函数在x0点处做泰勒展开,有:img
如果忽略2次以上的项,则有:
img
现在我们在x0点处,要以它为基础,找到导数为0的点,即导数为0。对上面等式两边同时求导,并令导数为0,可以得到下面的方程:
img
可以解得:
img
这样我们就得到了下一点的位置,从而走到x1。接下来重复这个过程,直到到达导数为0的点,由此得到牛顿法的迭代公式:img
给定初始迭代点x0,反复用上面的公式进行迭代,直到达到导数为0的点或者达到最大迭代次数。

2. 多元函数情况:

下面推广到多元函数的情况,如果读者对梯度,Hessian的概念还不清楚,请先去看微积分教材,或者阅读SIGAI之前关于最优化的公众号文章。根据多元函数的泰勒展开公式,我们对目标函数在x0点处做泰勒展开,有:
img
忽略二次及以上的项,并对上式两边同时求梯度,得到函数的导数(梯度向量)为:
img
其中即为Hessian矩阵,在后面我们写成H。令函数的梯度为0,则有:
img
这是一个线性方程组的解。如果将梯度向量简写为g,上面的公式可以简写为:
img
从初始点x0处开始,反复计算函数在处的Hessian矩阵和梯度向量,然后用下述公式进行迭代:
img
最终会到达函数的驻点处。其中称为牛顿方向。迭代终止的条件是梯度的模接近于0,或者函数值下降小于指定阈值。

(4)python实例

1. 一元函数:

代码如下:

from sympy import *
# step为迭代步数,x0为初始位置,obj为要求极值的函数
def newtons(step, x0, obj):
    i = 1 # 记录迭代次数的变量
    x0 = float(x0) # 浮点数计算更快
    obj_deri = diff(obj, x) # 定义一阶导数,对应上述公式
    obj_sec_deri = diff(obj, x, 2) # 定义二阶导数,对应上述公式
    while i <= step:
        if i == 1:
            # 第一次迭代的更新公式
            xnew = x0 - (obj_deri.subs(x, x0)/obj_sec_deri.subs(x, x0))
            print('迭代第%d次:%.5f' %(i, xnew))
            i = i + 1
        else:
            #后续迭代的更新公式
            xnew = xnew - (obj_deri.subs(x, xnew)/obj_sec_deri.subs(x, xnew))
            print('迭代第%d次:%.5f' % (i, xnew))
            i = i + 1
    return xnew
x = symbols("x") # x为字符变量
result = newtons(50, 10, x**6+x)
print('最佳迭代的位置:%.5f' %result)

结果如图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UvjjDKkX-1586158727496)(.\image-20200406153627471.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JQC0Q3ie-1586158727497)(.\image-20200406153608593.png)]

2. 二元函数:

代码如下:

"""
    用梯度法求二次函数f(x1,x2)=x1^2+2*x2^2-4*x1-2*x1*x2的极小值,极小点、
"""
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
 
def Fun(x1,x2):#原函数
    return x1*x1+2*x2*x2-4*x1-2*x1*x2
 
def PxFun(x1,x2):#偏x导
    return 2*x1-2*x2-4
 
def PyFun(x1,x2):#偏y导
    return 4*x2-2*x1
 
#初始化
i=0     #迭代次数
fig=plt.figure()#figure对象
ax=Axes3D(fig)#Axes3D对象
X1,X2=np.mgrid[-2:2:40j,-2:2:40j]#取样并作满射联合
Z=Fun(X1,X2)#取样点Z坐标打表
ax.plot_surface(X1,X2,Z,rstride=1,cstride=1,cmap="rainbow")
ax.set_xlabel('x1')
ax.set_ylabel('x2')
ax.set_zlabel('z')
 
#梯度下降
step=0.01   #下降系数
x1=0
x2=0#初始选取一个点
tag_x1=[x1]
tag_x2=[x2]
tag_z=[Fun(x1,x2)]#三个坐标分别打入表中,该表用于绘制点
new_x1=x1
new_x2=x2
Over=False
while Over==False:
    new_x1-=step*PxFun(x1,x2)
    new_x2-=step*PyFun(x1,x2)#分别作梯度下降
    if Fun(x1,x2)-Fun(new_x1,new_x2)<7e-9:#精度
        Over=True
    x1=new_x1
    x2=new_x2#更新旧点
    tag_x1.append(x1)
    tag_x2.append(x2)
    tag_z.append(Fun(x1,x2))#新点三个坐标打入表中
    i=i+1
 
#绘制点/输出坐标
ax.plot(tag_x1,tag_x2,tag_z,'r.')
plt.title('(x1,x2)~('+str(x1)+","+str(x2)+')')
plt.show()
print("迭代次数:",i)

结果如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mSkZqWNe-1586158727497)(.\image-20200406153721062.png)]

二. 梯度下降算法原理:

(1)梯度法三要素:

梯度法思想的三要素:出发点、下降方向、下降步长。

(2)类比:

在这儿,我们作个形象的类比,如果把这个走法类比为力,那么完整的三要素就是步长(走多少)、方向、出发点,这样形象的比喻,让我们对梯度问题的解决豁然开朗,出发点很重要,是初始化时重点要考虑的,而方向、步长就是关键。事实上不同梯度的不同就在于这两点的不同!

梯度方向是:
img
,步长设为常数Δ,这时就会发现,如果用在梯度较大的时候,离最优解比较远,W的更新比较快;然而到了梯度较小的时候,也就是较靠近最优解的时候,W的更新竟然也保持着跟原来一样的速率,这样会导致W很容易更新过度反而远离了最优解,进而出现在最优解附近来回震荡。所以,既然在远离最优解的时候梯度大,在靠近最优解的时候梯度小,我们让步长随着这个律动,于是我我们就用λ|W|来代替Δ,最后得到了我们熟悉的式子:
img
所以说这时的λ是随着坡度的陡缓而变化的,别看它是个常数。

(3)公式:

计算公式如下:
img

三. 总结

最小二乘法计算量偏大,而且求逆矩阵相当耗费时间,求逆矩阵也会存在数值不稳定的情况,相比之下梯度下降法可以看做是一种更简单的最小二乘法最后一步解方程的方法,梯度下降法虽然有一定的缺点,但是计算量不大,在数据量比较大的时候选择梯度下降法比较好一点。

参考文献:
[1]. https://blog.csdn.net/sigai_csdn/article/details/80678812

[2]. https://baijiahao.baidu.com/s?id=1613121229156499765&wfr=spider&for=pc

发布了2 篇原创文章 · 获赞 0 · 访问量 18

猜你喜欢

转载自blog.csdn.net/lk1252793766/article/details/105344940