梯度下降与一元线性回归

一、梯度下降

1.基本概念

梯度下降概念:梯度下降是求解无约束最优化问题最常用的方法,是人工智能基础算法之一。它通过迭代的思想一步步逼近目标函数,在每一次的过程中先求解当前位置的梯度向量(即求出当前函数的导数),并以负的梯度向量方向作为方向向量,求出下一次的函数(在该方向上函数下降速度最快),直到找到符合理想的极小值点为止。
梯度向量:函数在某点处变化最快速度最快,变化率最大的方向,变化率为梯度向量的模长。
梯度下降公式
θ i = θ i − α ∂ ∂ θ i J ( θ ) θ_i=θ_i−α\frac{∂}{∂θ_i}J(θ) θi=θiαθiJ(θ)

2.直观解释

梯度下降求极小值点问题可以类比为人下山最短路线问题。
人下山路线图
*左图为人下山在选择路线 *右图为下山的最短路线
问题描述:一个人要从山顶下山,他要如何选择下山路线以保证他下山的路线最短,最省力。
解题思路:要保证他下山路线最短,需要保证他下山的每一步是该处最斜的坡度。因为在此处坡度最斜的地方迈一小段的步长能获得最大的下山距离。且在下山时迈的步长越小,所走的整体下山路线越趋近于最短下山路线。因为朝最优方向行走的次数最多。

3.梯度下降求解步骤

设f(x1,x2,x3,…,xn)只有一个极小值点,初始给定参数X0 = (xn1,xn2,xn3,…,xn0),从该点开始如何找到该函数f(x)的极小值点?
方法:
(1) 首先自己按需求设定一个十分小的正数α(学习率,即步长), ε ε ε(迭代结束的比较参数,称为阈值)。
(2) 求当前位置函数关于某一自变量的偏导数
f ′ ( x m 0 ) = ∂ y ∂ x m ( x m 0 ) , m = 1 或 2 或 3 或 . . . 或 n f'(x_{m0})=\frac{∂y}{∂x_{m}}(x_{m0}),m=1或2或3或...或n f(xm0)=xmy(xm0),m=123...n
该处偏导数的值即为该点变化最大的斜率
(3) 修改当前函数。每一次下降后需要找到变化后的函数,以变化后的函数所在点为基准再次进行下降运算。
x m ′ = x m − α ∂ y ∂ x m ( x m 0 ) , m = 1 或 2 或 3 或 . . . 或 n x'_{m}=x_{m}-α\frac{∂y}{∂x_{m}}(x_{m0}),m=1或2或3或...或n xm=xmαxmy(xm0),m=123...n
(4) 比较函数变化值(与 ε ε ε对比),若变化值比 ε ε ε小结束循环,否则返回步骤(2)和步骤(3)继续循环,直至变化值比 ε ε ε小为止。
即判断 α ∂ y ∂ x m ( x m 0 ) , m = 1 或 2 或 3 或 . . . 或 n α\frac{∂y}{∂x_{m}}(x_{m0}),m=1或2或3或...或n αxmy(xm0),m=123...n是否小于 ε ε ε

4.梯度下降法所存在的问题

①迭代次数多,需要大量运算
②在下降过程中可能会出现“之”字形下降
③直线搜索时可能会遇到一些问题

5.例题介绍

在这里插入图片描述
例如该题
(1)已知学习率η = 0.9,阈值ε = 0.01
(2)y’ = x - 2
y0’ = -6
(3)x0 = -4
x1 = x0 - η × y0’ = -4 + 5.4 = 1.4
(4)Δx = 5.4 > ε,返回步骤(2)
(以下不再标注步骤顺序)
y1’ = -0.6
x2 = x1 - η × y1’ = 1.94
Δx = 0.54 > 0.01,继续循环
y2’ = -0.06
x3 = x2 - η × y2’ = 1.994
Δx = 0.054 > 0.01,继续循环
y3’ = -0.006
x4 = x3 - η × y3’ = 1.9994
Δx = 0.0054 < 0.01,结束循环
即x = 1.9994为该函数的极小值点
y = x^2/2 - 2x =1.99999982

6.梯度下降三兄弟(BGD、SGD、MBGD)

批量梯度下降法(Batch Gradient Descent)
批量梯度下降法每次都使用训练集中的所有样本更新参数。它得到的是一个全局最优解,但是每迭代一步,都要用到训练集所有的数据,如果 m 很大,那么迭代速度就会变得很慢。
优点:可以得出全局最优解。
缺点:样本数据集大时,训练速度慢。

#②随机梯度下降法(Stochastic Gradient Descent)
随机梯度下降法每次更新都从样本随机选择 1 组数据,因此随机梯度下降比批量梯度下降在计算量上会大大减少。SGD 有一个缺点是,其噪音较 BGD 要多,使得 SGD 并不是每次迭代都向着整体最优化方向。而且 SGD 因为每次都是使用一个样本进行迭代,因此最终求得的最优解往往不是全局最优解,而只是局部最优解。但是大的整体的方向是向全局最优解的,最终的结果往往是在全局最优解附近。
优点:训练速度较快。
缺点:过程杂乱,准确度下降。

#③小批量梯度下降法(Mini-batch Gradient Descent)
小批量梯度下降法对包含 n 个样本的数据集进行计算。综合了上述两种方法,既保证了训练速度快,又保证了准确度。

二、一元线性回归

1.线性回归概念

在回归分析中,如果只包含一个自变量和一个因变量可用一条直线近似表示,这种回归分析称为一元线性回归分析;如果回归分析中包含两个或两个以上的自变量,且因变量和自变量之间是线性关系,则称为多元线性回归分析
含义: 一元线性回归分析其实就是从一堆训练集中去算出一条直线,是数据集到直线之间的距离差最小。
在这里插入图片描述
*此图为在众多数据集中找出一条一元线性回归方程,尽可能使数据点到直线的距离最小

2.线性回归分析的一般形式

一元线性回归分析:Y = a + bx
多元线性回归分析:Y = a + b1X1 + b2X2 + … + bnXn
渐进回归模型: Y = a + b e − r X Y=a+be^{-rX} Y=a+berX
二次曲线回归模型: Y = a + b 1 X + b 2 X 2 Y=a+b_{1}X+b_{2}X^{2} Y=a+b1X+b2X2
双曲线模型:Y=a+\frac{b}
除此之外还有其他非线性回归分析形式,此处不再表示。

3.一元回归线性方程推导过程

设线性回归函数: h θ ( x ) = θ 0 + θ 1 x h_θ(x)=θ_0+θ_1x hθ(x)=θ0+θ1x构造损失函数(loss): J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(θ_{0},θ_{1})=\frac{1}{2m}\sum_{i=1}^{m}(h_{θ}(x^{(i)})-y^{(i)})^{2} J(θ0,θ1)=2m1i=1m(hθ(x(i))y(i))2思路:通过梯度下降法不断更新 θ 0 θ_{0} θ0 θ 1 θ_{1} θ1​,当损失函数的值特别小时,就得到了我们最终的函数模型。过程: J ( θ 0 , θ 1 ) = 1 2 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) 2 J(θ_{0},θ_{1})=\frac{1}{2m}\sum_{i=1}^{m}(h_{θ}(x^{(i)})-y^{(i)})^{2} J(θ0,θ1)=2m1i=1m(hθ(x(i))y(i))2step1. 求导: ∂ ∂ θ 0 J ( θ 0 , θ 1 ) = 1 m ∑ i = 1 m ( h θ ( x ) ( i ) − y ( i ) ) \frac{∂}{∂θ_{0}}J(θ_{0},θ_{1})=\frac{1}{m}\sum_{i=1} ^{m}(h_{θ}(x)^{(i)}-y^{(i)}) θ0J(θ0,θ1)=m1i=1m(hθ(x)(i)y(i)) ∂ ∂ θ 1 J ( θ 0 , θ 1 ) = 1 m ∑ i = 1 m ( h θ ( x ) ( i ) − y ( i ) ) ⋅ x ( i ) \frac{∂}{∂θ_{1}}J(θ_{0},θ_{1})=\frac{1}{m}\sum_{i=1} ^{m}(h_{θ}(x)^{(i)}-y^{(i)})·x^{(i)} θ1J(θ0,θ1)=m1i=1m(hθ(x)(i)y(i))x(i)step2. 更新 θ 0 θ_{0} θ0 θ 1 θ_{1} θ1 θ 0 = θ 0 − α ⋅ 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) θ_{0}=θ_{0}-α·\frac{1}{m}\sum_{i=1}^{m}(h_{θ}(x^{(i)})-y^{(i)}) θ0=θ0αm1i=1m(hθ(x(i))y(i)) θ 1 = θ 1 − α ⋅ 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) ⋅ x ( i ) θ_{1}=θ_{1}-α·\frac{1}{m}\sum_{i=1}^{m}(h_{θ}(x^{(i)})-y^{(i)})·x^{(i)} θ1=θ1αm1i=1m(hθ(x(i))y(i))x(i)step3. 代入损失函数,求损失函数的值,若得到的值小于 ε ε ε(一般为 0.01 或者 0.001 这样的小数),退出;否则,返回 step1。

4.代码实现

以下为通过梯度下降法实现一元线性回归的代码,分别使用了上述的 3 种梯度下降法:
1.批量梯度下降:
下面展示 python代码

import matplotlib.pyplot as plt
import matplotlib
from math import pow
from random import uniform

x = [1,3,5,7,9,11,13]
y = [100,111,130,144,149,166,179]

#线性回归方程为 y = theta0+theta1*x
#参数定义

theta0 = uniform(0,2)
thetal = uniform(0,2)
alpha = 0.1
m = len(x)
count = 0
loss = []

for num in range(10000):
    count += 1
    diss = 0 #误差
    deriv0 = 0 #对theta0 导数
    deriv1 = 0 #对theta1 导数
    for i in range(m):
        deriv0+= (theta0+theta1*x[i]-y[i])/m
        deriv1+= ((theta0+theta1*x[i]-y[i])/m)*x[i]
    #更新 theta0和theta1
    for i in range(m):
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m)
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]
    #求损失函数 J(θ)
    for i in range(m):
        diss = diss + (1/(2*m))*pow((theta0+theta1*x[i]-y[i]),2)
    loss.append(diss)

    #如果误差已经很小,可以退出循环
    if diss <= 0.001:
        break

    print("本次迭代次数为:{}次,最终得到theta0={},theta1={}".format(count,theta0,theta1))
    print("本次迭代得到的回归函数使:y={}+{}*x".dormat(theta0,theta1))
    #画原始数据图和得到的线性回归函数图
    matplotlib.rcParams['font.sans-serif'] = ['SiHei']
    plt.plot(x,y,'bo',label='数据')
    plt.plot(x,[theta0+theta1*x for x in x],label='线性回归函数')
    plt.xlabel('x')
    olt.ylabel('y')
    plt.legend()
    plt.show()
    #画损失函数(误差)变化图
    plt.scatter(range(count),loss)
    plt.show()

输出结果:本次迭代次数为:10000 次,最终得到 t h e t a 0 = 96.86808644268262 theta0=96.86808644268262 theta0=96.86808644268262 t h e t a 1 = 5.762687172041142 theta1=5.762687172041142 theta1=5.762687172041142本次迭代得到的回归函数是: y = 96.86808644268262 + 5.762687172041142 ∗ x y=96.86808644268262+5.762687172041142*x y=96.86808644268262+5.762687172041142x
2.随机梯度下降

import matplotlib.pyplot as plt
import matplotlib
from math import pow
import random
x = [1,3,5,7,9,11,13]
y = [100,111,130,144,149,166,179]
#线性回归函数为 y=theta0+theta1*x
#参数定义
theta0 = random.uniform(0,2)#对 theata0 随机赋值
theta1 = random.uniform(0,2)#对 theata1 随机赋值
alpha = 0.1#学习率
m = len(x)
count = 0
loss = []
for num in range(10000):
    count += 1
    diss = 0   #误差
    deriv0 = 0 #对 theata0 导数
    deriv1 = 0 #对 theata1 导数
    #求导
    for i in range(m):
        deriv0 += (theta0+theta1*x[i]-y[i])/m
        deriv1 += ((theta0+theta1*x[i]-y[i])/m)*x[i]
    #更新 theta0 和 theta1
    for i in range(m)
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m) 
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]
    #求损失函数 J (θ):
    rand_i = random.randrange(0,m)
    diss = diss + (1/(2*m))*pow((theta0+theta1*x[rand_i]-y[rand_i]),2)
    loss.append(diss)
    #如果误差已经很小,则退出循环
    if diss <= 0.001:
        break
    
print("本次迭代次数为:{}次,最终得到theta0={},theta1={}".format(count,theta0,theta1))
print("本次迭代得到的回归函数是:y={}+{}*x".format(theta0,theta1))
#画原始数据图和得到的线性回归函数图
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
plt.plot(x,y,'bo',label='数据')
plt.plot(x,[theta0+theta1*x for x in x],label='线性回归函数')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
#画损失函数(误差)变化图
plt.scatter(range(count),loss)
plt.show()

注意:因为是随机的,所以每次的结果会不一样。输出结果:本次迭代次数为:159 次,最终得到 t h e t a 0 = 94.02334615793364 theta0=94.02334615793364 theta0=94.02334615793364 t h e t a 1 = 5.968813991236714 theta1=5.968813991236714 theta1=5.968813991236714本次迭代得到的回归函数是: y = 94.02334615793364 + 5.968813991236714 ∗ x y=94.02334615793364+5.968813991236714*x y=94.02334615793364+5.968813991236714x
3.小批量梯度下降

import matplotlib.pyplot as plt
import matplotlib
from math import pow
import random
x = [1,3,5,7,9,11,13]
y = [100,111,130,144,149,166,179]
#目标函数为 y=theta0+theta1*x
#参数定义
theta0 = random.uniform(0,2)#对 theata0 随机赋值
theta1 = random.uniform(0,2)#对 theata1 随机赋值
alpha = 0.1#学习率
m = len(x)
count = 0
loss = []
for num in range(10000):
    count += 1
    diss = 0   #误差
    deriv0 = 0 #对 theta0 导数
    deriv1 = 0 #对 theta1 导数
    #求导
    for i in range(m):
        deriv0 += (theta0+theta1*x[i]-y[i])/m
        deriv1 += ((theta0+theta1*x[i]-y[i])/m)*x[i]
    #更新 theta0 和 theta1
    for i in range(m):
        theta0 = theta0 - alpha*((theta0+theta1*x[i]-y[i])/m) 
        theta1 = theta1 - alpha*((theta0+theta1*x[i]-y[i])/m)*x[i]
    #求损失函数 J (θ)
    rand_ls = list(range(3))
    for i in range(3):
        rand_i = random.randrange(0,m)
        rand_ls[i] = rand_i
    for i in rand_ls:
        diss = diss + (1/(2*m))*pow((theta0+theta1*x[i]-y[i]),2)
    loss.append(diss)
    #如果误差已经很小,则退出循环
    if diss <= 0.001:
        break
    
print("本次迭代次数为:{}次,最终得到theta0={},theta1={}".format(count,theta0,theta1))
print("本次迭代得到的回归函数是:y={}+{}*x".format(theta0,theta1))
#画原始数据图和得到的线性回归函数图
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
plt.plot(x,y,'bo',label='数据')
plt.plot(x,[theta0+theta1*x for x in x],label='线性回归函数')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
plt.show()
#画损失函数(误差)变化图
plt.scatter(range(count),loss)
plt.show()

输出结果:本次迭代次数为:10000 次,最终得到 t h e t a 0 = 96.86808644268262 theta0=96.86808644268262 theta0=96.86808644268262 t h e t a 1 = 5.762687172041142 theta1=5.762687172041142 theta1=5.762687172041142本次迭代得到的回归函数是: y = 96.86808644268262 + 5.762687172041142 ∗ x y=96.86808644268262+5.762687172041142*x y=96.86808644268262+5.762687172041142x

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值