Python实现批量梯度下降 随机梯度下降 小批量梯度下降 代码

在学习了有关梯度下降算法后,自己动手实现了一遍,选用的也是最为简单的线性回归作为例子

梯度下降的的相关原理及推导网上有很多,由于个人不擅长推理总结,我就不再画蛇添足了,贴几个我看完之后觉的不错的帖子,在此感谢各位博主

深度解读最流行的优化算法:梯度下降

一文看懂常用的梯度下降算法

梯度下降的三种形式BGD、SGD、以及MBGD

梯度下降的三种形式BGD、SGD、以及MBGD

最后两个是不同的博客,但他们的标题相同

三种算法中文名分别为

  1. 批量梯度下降(Batch gradient descent)

  2. 随机梯度下降(Stochastic gradient descent)

  3. 小批量梯度下降(Mini-batch gradient descent)

不过都叫梯度下降算法,可见他们的核心是没有变的,变化的只是取训练集的方式,而梯度下降最核心的就是对函数求偏导,这个是在高等数学里有的。

首先是BGD,他是使用所有数据集进行训练。具体代码为:

import  matplotlib.pyplot as plt
import random
import matplotlib

#生成数据
def data():
    x = range(10)
    y = [(2*s+4) for s in x]
    for i in range(10):
        y[i] = y[i]+random.randint(0,8)-4
    return x, y

#使用梯度下降进行训练
def diedai(x,y):
    flag = True
    a = random.randint(0,5)
    b = random.randint(0,10)
    m = len(x)
    arf = 0.005 #学习率
    n = 0
    sum1 = 0
    sum2 = 0
    exp = 0.000001
    error0 = 0
    error1 = 0
    while flag:

        for i in range(m):  #计算对应的偏导数
            sum1 = a*x[i]+b-y[i]
            sum2 = (a*x[i]+b-y[i])*x[i]
            error1 = (a*x[i]+b-y[i])**2
        a = a - sum2*arf/m  #对a,b进行更新
        b = b - sum1*arf/m

        if abs(error1-error0)<exp: #计算误差
            break
        error0 = error1
        print('a=%f,b=%f,error=%f' % (a, b, error1))

        if n > 500:
            #flag = False
            break
        n += 1
        if n % 10 == 0:
            print('第%d次迭代:a=%f,b=%f' % (n, a, b))
    return a,b

#使用最小二乘法计算结果
def calculation(x, y):
    c1 = 0
    c2 = 0
    c3 = 0
    c4 = 0
    n = len(x)
    for i in range(n):
        c1 += x[i]*y[i]
        c2 += x[i]*x[i]
        c3 += x[i]
        c4 += y[i]
    a = (n*c1-c3*c4) /( n*c2-c3*c3)  #利用公式计算a, b
    b = (c2*c4-c3*c1) / (n*c2-c3*c3)
    return a, b


if __name__ == '__main__':
    x,y = data()

    a1,b1 = diedai(x,y)
    X1 = range(10)
    Y1 = [(a1*s+b1) for s in X1]
    print('梯度下降y=%fX+%f'%(a1,b1))

    a2,b2 = calculation(x,y)
    X2 = range(10)
    Y2 = [(a2*s+b2) for s in X2]
    print('最小二乘法y=%fX+%f'%(a2,b2))

    matplotlib.rcParams['font.sans-serif'] = ['SimHei'] #设置字体中文,防止乱码
    plt.scatter(x, y, color = 'red',label = '数据')
    plt.plot(X1, Y1, color = 'blue',label = '梯度下降')
    plt.plot(X2, Y2, color = 'green',label = '最小二乘法')
    plt.legend()
    plt.show()

这里我使用了最小二乘法作为参考

训练的结果为


可以很明显的看出,两种方法是存在偏差的,至于原因我也很想知道,也许是梯度下降算法作为迭代算法迭代的不够彻底,不过这也只是我的猜测,希望谁知道的能和我透露一下

批量梯度下降算法由于是使用了所有的数据集,因此,当数据集很大时,他的计算会出现溢出,或者计算时间非常长的问题,而随机梯度下降算法就很好的解决了问题,他的每次迭代使用的是一组数据,也就是一个结果(y)和他对应的变量(x),下面是他的代码:

from matplotlib import pyplot as plt
import  random


#生成数据
def data():
    x = range(10)
    y = [(2*i+4) for i in x]
    for i in range(10):
        y[i] = y[i]+random.randint(0,8)-4
    return x,y


#使用随机梯度下降训练
def SGD(x,y):
    error0 = 0
    step_size = 0.001
    esp = 1e-6
    #a = random.randint(0,4)
    #b = random.randint(0,8)
    a = 1.2  #将给a,b随机赋初始值
    b = 3.5
    m = len(x)
    n = 0
    while True:
        i = random.randint(0,m-1)
        print(i)
        sum0 = a * x[i] + b - y[i]
        sum1 = (a * x[i] + b - y[i])*x[i]
        error1 = (a * x[i] + b - y[i])**2  #计算模型和结果的误差

        a = a - sum1*step_size/m
        b = b - sum0*step_size/m
        print('a=%f,b=%f,error=%f'%(a,b,error1))

        if abs(error1-error0)<esp:  #误差很小,可以终止迭代
            break
        error0 = error1
        n = n+1
        if n%20==0:
            print('第%d次迭代'%n)
        if (n>500):
            break
    return a,b
if __name__ == '__main__':
    x,y = data()
    a,b = SGD(x,y)
    X = range(10)
    Y = [(a*i+b) for i in X]

    plt.scatter(x,y,color='red')
    plt.plot(X,Y)
    plt.show()
运算结果为:


和批量梯度下降算法一样他也能很好的得到结果,不过这个算法也存在缺陷,那就是由于每次迭代只是用一组数据,因此他受噪声/离群点/异常值的影响非常大,由此有了一种折中的方法,那就只小批量梯度下降算法,他在每次迭代时使用一批数据,这批数据可以自行选择也可以随机产生,大小也可自由自定,越大越接近批量梯度下降算法,越小越接近随机梯度下降算法,下面是我的代码:

from  matplotlib import pyplot as plt
import random

#生成数据
def data():
    x = range(10)
    y = [(3*i+2) for i in x]
    for i in range(len(y)):
        y[i] = y[i]+random.randint(0,5)-3
    return x,y

#用小批量梯度下降算法进行迭代
def MBGD(x,y):
    error0 = 0
    error1 = 0
    n = 0
    m = len(x)
    esp = 1e-6
    step_size = 0.01  #选择合理的步长
    a = random.randint(0,10)  #给a,b赋初始值
    b = random.randint(0,10)
    while True:
        trainList = []
        for i in range(5):  #创建随机的批量
            trainList.append(random.randint(0,m-1))

        for i in range(5):  #对数据进行迭代计算
            s = trainList[i]
            sum0 = a*x[s]+b-y[s]
            sum1 = (a*x[s]+b-y[s])*x[s]
            error1 = error1+(a*x[s]+b-y[s])**2
        a = a - sum1*step_size/m
        b = b - sum0*step_size/m
        print('a=%f,b=%f,error=%f'%(a,b,error1))

        if error1-error0<esp:
            break

        n = n+1
        if n>500:
            break
    return a, b
if __name__ == '__main__':
    x,y = data()
    a,b = MBGD(x,y)
    X = range(len(x))
    Y = [(a*i+b) for i in X]

    plt.scatter(x,y,color='red')
    plt.plot(X,Y,color='blue')
    plt.show()

运行结果为:

这就是三种梯度下降算法了,有什么问题欢迎各位指正



  • 11
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值