栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

最小二乘问题-梯度下降法(附Python代码)

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

最小二乘问题-梯度下降法(附Python代码)

         本题中我使用到了最速下降法来拟合函数,一开始我使用了高斯牛顿法计算了第一道题目,但是在代入最小二乘那个矩阵的公式时发现矩阵不可逆,因此直接否定了这个方法不适用于这道题目,后来决定使用最速下降法,因为该方法适用场合很广且十分简便,但是收敛速度不佳。算法思路十分简单,直接把上面的问题看成是无约束优化问题,寻找残差方程求和的最小值,首先求出该方程的梯度,然后随机选个初始点,一直沿着梯度方向迭代即可。

 

        

        通过程序计算,最后优化执行的结果的精确度较高,运行速度很慢,我使用的一维线搜索方法采用了精确线搜索黄金分割法,初始边界取了0到3。设置的精度是1e-5,大约执行了8万次迭代耗时5分钟才得到最后结果,求出的结果,以及点带入残差方程值如下:

        收敛性简单分析:首先通过表面运行时间来看发现这个算法的收敛速度是非常慢的,并且随的精度的提高,运行的时间越来越长,比如说我设置不同的epsion值,1e-4时迭代了20000次左右,1e-5迭代了80000次左右。

        在一般情况下,当用最速下降法寻找极小点时,其搜索路径呈直角锯齿状,如下图,

 

        这也就意味着开头几步下降的快,但是越到后面,下降速度越来越慢,通过证明可以的知梯度下降法的收敛速度是线性的。

        在一维线搜索中,我采用了精确性搜索,这存在一些问题,首先是速度慢,而且在这里只是追求了该点下降最陡的方向,但是并不意味着该点就是下降最多的点,而且算法会因此变得不灵活因为,程序每次都要求出fai(x)=f(xk+akdk)的最小值,如果遇到更加复杂的函数,会有很大的麻烦,有可能找不到这个最小值。

import math
import numpy as np
e=math.e
def emi(a,b):
    return a*(e**b)
def t(k):
    return 0.1*k
def y(k):
    return emi(1,-t(k))-emi(5,-10*t(k))+emi(3,-4*t(k))
def function(x):                        #返回函数即残差方程的求和,传入的x是array类型或matrix 6维向量
    if (type(x) == np.matrix):
        q = np.array(x)
        x1,x2,x3,x4,x5,x6 = q[0][0],q[0][1],q[0][2],q[0][3],q[0][4],q[0][5]
    else:
        x1,x2,x3,x4,x5,x6 = x[0],x[1],x[2],x[3],x[4],x[5]
    sum=0
    for k in range(1,8):
        sum+= (emi(x3,-t(k)*x1)-emi(x4,-t(k)*x2)+emi(x6,-t(k)*x5)-y(k))**2
    return sum
def r(x,k):                   #返回点代入残差方程的值
    if (type(x) == np.matrix):
        q = np.array(x)
        x1, x2, x3, x4, x5, x6 = q[0][0], q[0][1], q[0][2], q[0][3], q[0][4], q[0][5]
    else:
        x1, x2, x3, x4, x5, x6 = x[0], x[1], x[2], x[3], x[4], x[5]
    return (emi(x3,-t(k)*x1)-emi(x4,-t(k)*x2)+emi(x6,-t(k)*x5)-y(k))**2
def grade(x):                #返回梯度值
    if (type(x) == np.matrix):
        q = np.array(x)
        x1, x2, x3, x4, x5, x6 = q[0][0], q[0][1], q[0][2], q[0][3], q[0][4], q[0][5]
    else:
        x1, x2, x3, x4, x5, x6 = x[0], x[1], x[2], x[3], x[4], x[5]
    a1,a2,a3,a4,a5,a6=0,0,0,0,0,0
    for k in range(1,8):
        a1 += 2 * (emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(-t(k) * x3, -t(k) * x1))
        a2 += 2*(emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(t(k) * x4, -t(k)*x2))
        a3 += 2*(emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(1, -t(k) * x1))
        a4 += 2*(emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(-1, -t(k) * x2))
        a5 += 2 * (emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(-t(k) * x6, -t(k) * x5))
        a6 += 2 * (emi(x3, -t(k) * x1) - emi(x4, -t(k) * x2) + emi(x6, -t(k) * x5) - y(k)) * (emi(1, -t(k) * x5))
    return np.matrix([a1,a2,a3,a4,a5,a6])
def fai(p, x, d):              #用于一维搜索的函数
    q = x + p * d
    return function(q)
def gold(x, d):               #黄金分割法
    a, b, k, e = [0], [3], 0, 1e-5
    l, r = [a[0] + 0.382 * (b[0] - a[0])], [a[0] + 0.618 * (b[0] - a[0])]
    fl, fr = [fai(l[0], x, d)], [fai(r[0], x, d)]
    while (1):
        if (fl[k] > fr[k]):
            if (b[k] - l[k] <= e):
                return r[k]
            a.append(l[k])
            b.append(b[k])
            l.append(r[k])
            fl.append(fr[k])
            r.append(a[k + 1] + 0.618 * (b[k + 1] - a[k + 1]))
            fr.append(fai(r[k + 1], x, d))
        else:
            if (r[k] - a[k] <= e):
                return l[k]
            a.append(a[k])
            b.append(r[k])
            r.append(l[k])
            fr.append(fl[k])
            l.append(a[k + 1] + 0.382 * (b[k + 1] - a[k + 1]))
            fl.append(fai(l[k + 1], x, d))
        k += 1
eps = 1e-5                   
x = [np.array([1, 1, 1, 1,1,1])]
g = []
d = []
alpha=[]
k = 0
while (1):
    print("第%d次迭代:"%k)
    print(x[k])
    g.append(grade(x[k]))
    if(np.linalg.norm(g[k])<=eps):
        break
    d.append(-g[k])
    alpha.append(gold(x[k],d[k]))
    x.append(x[k]+alpha[k]*d[k])
    k += 1
for i in range (1,8):
    print("第%d个点代入拟合函数的偏差值为:%lf"%(i,r(x[k],i)))

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/968693.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号