手撸梯度下降和python实现

一、概念与算法原理

1.1 梯度

  • 从几何意义上讲,梯度就是函数变化增加最快的地方.
  • 在微积分里面,对多元函数的参数求 ∂ \partial 偏导数,把求得的各个参数的偏导数以向量的形式写出来,就是梯度。如函数 f ( x , y ) f(x,y) f(x,y),其梯度向量为 ( ∂ f ∂ x , ∂ f ∂ y ) T (\frac{∂f}{∂x}, \frac{∂f}{∂y})^T (xf,yf)T,简称 g r a d f ( x , y ) grad f(x,y) gradf(x,y) 或者 ▽ f ( x , y ) ▽f(x,y) f(x,y) 。如果是3个参数的向量梯度,就是 ( ∂ f ∂ x , ∂ f ∂ y , ∂ f ∂ z , ) T (\frac{∂f}{∂x}, \frac{∂f}{∂y},\frac{∂f}{∂z},)^T (xf,yf,zf,)T ,以此类推。

1.2 梯度下降

1.2.1 梯度下降相关概念

  • 步长(Learning rate):步长决定了在梯度下降迭代的过程中,每一步沿梯度负方向前进的长度。

  • 特征(feature):指的是样本中输入部分,比如2个样本、1个特征的数据集 { ( x ( 0 ) , y ( 0 ) ) , ( x ( 1 ) , y ( 1 ) ) } \{(x^{(0)},y^{(0)}),(x^{(1)},y^{(1)})\} {(x(0),y(0)),(x(1),y(1))},则第一个样本特征为 x ( 0 ) x^{(0)} x(0) ,第一个样本输出为 y ( 0 ) y^{(0)} y(0)

  • 假设函数(hypothesis function):在监督学习中,为了拟合输入样本,而使用的假设函数,记为 h θ ( x ) h_{\theta}(x) hθ(x) 。比如对于1个特征的n个样本 ( x ( i ) , y ( i ) ) ( i = 1 , 2 , . . . , n ) (x^{(i)},y^{(i)})(i=1,2,...,n) (x(i),y(i))(i=1,2,...,n),其假设函数可写成:
    h θ ( x ) = θ 0 + θ 1 x h_{\theta}(x) = \theta_{0}+\theta_{1}x hθ(x)=θ0+θ1x

  • 损失函数(loss function):为了评估模型拟合的好坏,通常用损失函数来度量拟合的程度。损失函数极小化,意味着拟合程度最好,对应的模型参数即为最优参数。在线性回归中,损失函数通常为样本输出和假设函数的差取平方。比如对于1个特征的n个样本 ( x ( i ) , y ( i ) ) ( i = 1 , 2 , . . . , n ) (x^{(i)},y^{(i)})(i=1,2,...,n) (x(i),y(i))(i=1,2,...,n),其线性回归的损失函数为:
    J ( θ 0 , θ 1 ) = ∑ i = 0 n ( h θ ( x ) ( i ) − y ( i ) ) 2 = ∑ i = 0 n [ ( θ 0 ( i ) + θ 1 ( i ) x 1 ( i ) ) − y ( i ) ] 2 \begin{aligned} J(\theta_{0},\theta_{1}) & = \sum_{i=0}^{n}(h_{\theta}(x)^{(i)} - y^{(i)})^{2} \\ & = \sum_{i=0}^{n}[(\theta_{0}^{(i)}+\theta_{1}^{(i)}x_{1}^{(i)}) - y^{(i)}]^{2} \end{aligned} J(θ0,θ1)=i=0n(hθ(x)(i)y(i))2=i=0n[(θ0(i)+θ1(i)x1(i))y(i)]2

  • 梯度下降不一定能够找到全局的最优解,有可能是一个局部最优解。当然,如果损失函数是凸函数,梯度下降法得到的解就一定是全局最优解。
    在这里插入图片描述

1.2.2 梯度下降的详细算法

(1)代数描述
  • 1.先决条件: 确认优化模型的假设函数和损失函数。
        比如对于m个特征的线性回归,假设函数表示为 h θ ( x 1 , x 2 , . . . , x m ) = θ 0 + θ 1 x 1 + . . . + θ m x m h_{\theta}(x_{1},x_{2},...,x_{m}) = \theta_{0}+\theta_{1}x_{1}+...+\theta_{m}x_{m} hθ(x1,x2,...,xm)=θ0+θ1x1+...+θmxm,其中 θ i ( i = 0 , 1 , . . . , m ) \theta_{i}(i=0,1,...,m) θi(i=0,1,...,m) 为模型参数, x i ( i = 1 , 2 , . . . , m ) x_{i}(i=1,2,...,m) xi(i=1,2,...,m)为每个样本的m个特征值。为了表示可以简化,可以设 x 0 = 1 x_{0}=1 x0=1,假设函数则可以简化为
    h θ ( x 0 , x 1 , . . . , x m ) = ∑ i = 0 m θ i x i h_{\theta}(x_{0},x_{1},...,x_{m}) = \sum_{i=0}^{m} \theta_{i}x_{i} hθ(x0,x1,...,xm)=i=0mθixi
    对应于上面的假设函数,损失函数为:
    J ( θ 0 , θ 1 , . . . , θ m ) = 1 2 n ∑ i = 1 n [ h θ ( x 0 ( i ) , x 1 ( i ) , . . . , x m ( i ) ) − y ( i ) ] 2 \begin{aligned} J(\theta_{0},\theta_{1},...,\theta_{m}) = \frac{1}{2n} \sum_{i=1}^{n} [h_{\theta}(x_{0}^{(i)},x_{1}^{(i)},...,x_{m}^{(i)})-y^{(i)}]^{2} \end{aligned} J(θ0,θ1,...,θm)=2n1i=1n[hθ(x0(i),x1(i),...,xm(i))y(i)]2
    其中, n n n 是样本量, m m m 是特征数,加 1 2 n \frac{1}{2n} 2n1是为了更好地理解,也方便求偏导后抵消2次幂。

  • 2.算法相关参数初始化:参数 θ \theta θ,步长 α \alpha α,终止距离(即梯度下降的距离) ε \varepsilon ε

  • 3.算法过程
      1)确认梯度函数。
      2)用步长乘以损失函数的梯度,得到当前位置下降的距离。如参数 θ i ( i = 0 , 1 , . . . , m ) \theta_{i}(i=0,1,...,m) θi(i=0,1,...,m) 的梯度为 ∂ J ( θ ) ∂ θ i \frac{\partial J(\theta)}{\partial \theta_{i}} θiJ(θ),梯度下降的距离为 α ∂ J ( θ ) ∂ θ i \alpha \frac{\partial J(\theta)}{\partial \theta_{i}} αθiJ(θ),即
    d = α 1 n ∑ i = 1 n [ h θ ( x 0 ( i ) , x 1 ( i ) , . . . , x m ( i ) ) − y ( i ) ] x ( i ) d = \alpha \frac{1}{n} \sum_{i=1}^{n} [h_{\theta}(x_{0}^{(i)},x_{1}^{(i)},...,x_{m}^{(i)})-y^{(i)}]x^{(i)} d=αn1i=1n[hθ(x0(i),x1(i),...,xm(i))y(i)]x(i)
      3)确定是否所有的 θ i ( i = 0 , 1 , . . . , m ) \theta_{i}(i=0,1,...,m) θi(i=0,1,...,m)梯度下降的距离都小于 ε \varepsilon ε,如果小于 ε \varepsilon ε 则算法终止,否则进入步骤4.
      4)更新所有的 θ i ( i = 0 , 1 , . . . , m ) \theta_{i}(i=0,1,...,m) θi(i=0,1,...,m),更新完毕后继续转入步骤1。
    θ i : = θ i − d = θ i − α 1 n ∑ i = 1 n [ h θ ( x 0 ( i ) , x 1 ( i ) , . . . , x m ( i ) ) − y ( i ) ] x ( i ) \begin{aligned} \theta_{i} & := \theta_{i} - d \\ & =\theta_{i} - \alpha \frac{1}{n} \sum_{i=1}^{n} [h_{\theta}(x_{0}^{(i)},x_{1}^{(i)},...,x_{m}^{(i)})-y^{(i)}]x^{(i)} \end{aligned} θi:=θid=θiαn1i=1n[hθ(x0(i),x1(i),...,xm(i))y(i)]x(i)

(2)矩阵描述
  • 这一部分是梯度下降法的矩阵公式,不再讲解。
  • 如果需要熟悉矩阵求导建议参考张贤达的《矩阵分析与应用》一书。
    目 标 函 数 : h θ ( X ) = X θ 损 失 函 数 : J ( θ ) = 1 2 ( X θ − Y ) T ( X θ − Y ) 损 失 函 数 偏 导 : ∂ ∂ θ J ( θ ) = X T ( X θ − Y ) 梯 度 下 降 距 离 : α X T ( X θ − Y ) 参 数 更 新 : θ : = θ − α X T ( X θ − Y ) \begin{aligned} &目标函数:h_{\theta}(X) = X \theta \\ &损失函数:J(\theta) = \frac{1}{2}(X \theta-Y)^{T}(X \theta-Y) \\ &损失函数偏导:\frac{\partial}{\partial \theta} J(\theta) = X^{T} ( X\theta-Y) \\ &梯度下降距离:\alpha X^{T} ( X\theta-Y) \\ &参数更新:\theta := \theta - \alpha X^{T} ( X\theta-Y) \end{aligned} hθ(X)=XθJ(θ)=21(XθY)T(XθY)θJ(θ)=XT(XθY)αXT(XθY)θ:=θαXT(XθY)

二、案例实战

  • 设原函数 h θ ( x ) = θ 0 + θ 1 x h_{\theta}(x) = \theta_{0}+\theta_{1}x hθ(x)=θ0+θ1x,我们使用以下五个数据点来拟合该函数。(正确解: h = 1 + 2 x h= 1+2x h=1+2x
n12345
x12345
y357911

2.1 手撸(代数形式)

  1)定义梯度公式,该案例有五个样本,两个 θ \theta θ,所以损失函数的梯度有:
∇ θ 0 = 1 5 ∑ i = 1 5 [ ( θ 0 ( i ) + θ 1 ( i ) x ( i ) ) − y ( i ) ] x 0 ( i ) ∇ θ 1 = 1 5 ∑ i = 1 5 [ ( θ 0 ( i ) + θ 1 ( i ) x ( i ) ) − y ( i ) ] x 0 ( i ) \nabla_{\theta_{0}} = \frac{1}{5} \sum_{i=1}^{5} [(\theta_{0}^{(i)}+\theta_{1}^{(i)}x^{(i)})-y^{(i)}]x_{0}^{(i)} \\ \nabla_{\theta_{1}} = \frac{1}{5} \sum_{i=1}^{5} [(\theta_{0}^{(i)}+\theta_{1}^{(i)}x^{(i)})-y^{(i)}]x_{0}^{(i)} θ0=51i=15[(θ0(i)+θ1(i)x(i))y(i)]x0(i)θ1=51i=15[(θ0(i)+θ1(i)x(i))y(i)]x0(i)
其中, x 0 ( i ) = 1 x_{0}^{(i)}=1 x0(i)=1.(不明白这里可以查看上文)

  2)定义梯度下降的距离公式,该案例有五个样本,两个 θ \theta θ,所以梯度下降的距离有:
d 0 = α ∇ θ 0 d 1 = α ∇ θ 1 d0 = \alpha \nabla_{\theta0} \\ d1 = \alpha \nabla_{\theta1} d0=αθ0d1=αθ1
其中, x 0 ( i ) = 1 x_{0}^{(i)}=1 x0(i)=1.(不明白这里可以查看上文)

  3)定义 θ \theta θ 更新公式 :
θ 0 : = θ 0 − d 0 θ 1 : = θ 1 − d 1 \theta_{0} := \theta_{0} - d0 \\ \theta_{1} := \theta_{1} - d1 θ0:=θ0d0θ1:=θ1d1

  4)初始化相关参数
α = 0.01 θ 0 = 0 , θ 1 = 0 ε = 0.001 \begin{aligned} & \alpha = 0.01 \\ & \theta_{0} = 0, \theta_{1} = 0 \\ & \varepsilon = 0.001 \end{aligned} α=0.01θ0=0,θ1=0ε=0.001

  5)算法过程:把 1 n \frac{1}{n} n1去掉不计算,且注意 x 0 i = 1 x_{0}^{i}=1 x0i=1
迭代第0次,计算出:
    两个 θ \theta θ损失函数梯度为
∇ θ 0 = 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 3 ] ∗ 1 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 5 ] ∗ 1 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 7 ] ∗ 1 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 9 ] ∗ 1 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 11 ] ∗ 1 = − 0.2 ∗ ( 3 + 5 + 7 + 9 + 11 ) = − 7 \begin{aligned} \nabla_{\theta_{0}} & = \frac{1}{5} * [(0*1+0*2) - 3]*1 \\ & + \frac{1}{5} * [(0*1+0*2) - 5]*1 \\ & + \frac{1}{5} * [(0*1+0*2) - 7]*1 \\ & + \frac{1}{5} * [(0*1+0*2) - 9]*1 \\ & + \frac{1}{5} * [(0*1+0*2) - 11]*1 \\ & = -0.2*(3+5+7+9+11) \\ & = -7 \end{aligned} θ0=51[(01+02)3]1+51[(01+02)5]1+51[(01+02)7]1+51[(01+02)9]1+51[(01+02)11]1=0.2(3+5+7+9+11)=7
∇ θ 1 = 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 3 ] ∗ 1 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 5 ] ∗ 2 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 7 ] ∗ 3 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 9 ] ∗ 4 + 1 5 ∗ [ ( 0 ∗ 1 + 0 ∗ 2 ) − 11 ] ∗ 5 = 0.2 ∗ ( 3 + 10 + 21 + 46 + 55 ) = 25 \begin{aligned} \nabla_{\theta_{1}} & = \frac{1}{5} * [(0*1+0*2) - 3]*1 \\ & + \frac{1}{5} * [(0*1+0*2) - 5]*2 \\ & + \frac{1}{5} * [(0*1+0*2) - 7]*3 \\ & + \frac{1}{5} * [(0*1+0*2) - 9]*4 \\ & + \frac{1}{5} * [(0*1+0*2) - 11]*5 \\ & = 0.2*(3+10+21+46+55) \\ & = 25 \end{aligned} θ1=51[(01+02)3]1+51[(01+02)5]2+51[(01+02)7]3+51[(01+02)9]4+51[(01+02)11]5=0.2(3+10+21+46+55)=25
    两个 θ \theta θ损失函数梯度下降距离为
d 0 = 0.01 ∗ ∇ θ 0 = 0.01 ∗ ( − 7 ) = − 0.07 d 1 = 0.01 ∗ ∇ θ 1 = 0.01 ∗ ( − 27 ) = − 0.25 \begin{aligned} d0 & = 0.01*\nabla_{\theta_{0}} =0.01*(-7) = -0.07 \\ d1 & = 0.01*\nabla_{\theta_{1}} =0.01*(-27) = -0.25 \end{aligned} d0d1=0.01θ0=0.01(7)=0.07=0.01θ1=0.01(27)=0.25

    终止迭代判断:两个 θ \theta θ梯度下降的距离都大于设定的阈值 ε \varepsilon ε,继续迭代。
∣ d 0 ∣ = 0.07 > ε = 0.001 & ∣ d 2 ∣ = 0.25 > ε = 0.001 \begin{aligned} |d0| = 0.07 & > \varepsilon =0.001\\ & \& \\ |d2| = 0.25 & > \varepsilon =0.001\\ \end{aligned} d0=0.07d2=0.25>ε=0.001&>ε=0.001

迭代第1次,计算出:
    更新两个 θ \theta θ
θ 0 : = θ 0 − d 0 = 0 + 0.07 = 0.07 θ 1 : = θ 1 − d 1 = 0 + 0.25 = 0.25 \theta_{0} := \theta_{0} - d0 =0+0.07 = 0.07 \\ \theta_{1} := \theta_{1} - d1 = 0+0.25=0.25 θ0:=θ0d0=0+0.07=0.07θ1:=θ1d1=0+0.25=0.25

    两个 θ \theta θ损失函数梯度为
∇ θ 0 = 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 3 ] ∗ 1 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 5 ] ∗ 1 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 7 ] ∗ 1 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 9 ] ∗ 1 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 11 ] ∗ 1 = − 0.2 ∗ ( 2.423 + 4.43 + 6.43 + 8.43 + 10.43 ) = − 6.4286 \begin{aligned} \nabla_{\theta_{0}} & = \frac{1}{5} * [(0.07*1+0.25*2) - 3]*1 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 5]*1 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 7]*1 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 9]*1 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 11]*1 \\ & = -0.2*(2.423+4.43+6.43+8.43+10.43) \\ & = -6.4286 \end{aligned} θ0=51[(0.071+0.252)3]1+51[(0.071+0.252)5]1+51[(0.071+0.252)7]1+51[(0.071+0.252)9]1+51[(0.071+0.252)11]1=0.2(2.423+4.43+6.43+8.43+10.43)=6.4286
∇ θ 0 = 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 3 ] ∗ 1 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 5 ] ∗ 2 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 7 ] ∗ 3 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 9 ] ∗ 4 + 1 5 ∗ [ ( 0.07 ∗ 1 + 0.25 ∗ 2 ) − 11 ] ∗ 5 = − 0.2 ∗ ( 2.423 + 8.86 + 19.29 + 33.72 + 52.15 ) = − 23.289 \begin{aligned} \nabla_{\theta_{0}} & = \frac{1}{5} * [(0.07*1+0.25*2) - 3]*1 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 5]*2 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 7]*3 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 9]*4 \\ & + \frac{1}{5} * [(0.07*1+0.25*2) - 11]*5 \\ & = -0.2*(2.423+8.86+19.29+33.72+52.15) \\ & = -23.289 \end{aligned} θ0=51[(0.071+0.252)3]1+51[(0.071+0.252)5]2+51[(0.071+0.252)7]3+51[(0.071+0.252)9]4+51[(0.071+0.252)11]5=0.2(2.423+8.86+19.29+33.72+52.15)=23.289

    两个 θ \theta θ损失函数梯度下降距离为
d 0 = 0.01 ∗ ∇ θ 0 = 0.01 ∗ ( − 6.4286 ) = − 0.064286 d 1 = 0.01 ∗ ∇ θ 1 = 0.01 ∗ ( − 23.289 ) = − 0.23289 \begin{aligned} d0 & = 0.01*\nabla_{\theta_{0}} =0.01*(-6.4286) = -0.064286 \\ d1 & = 0.01*\nabla_{\theta_{1}} =0.01*(-23.289) = -0.23289 \end{aligned} d0d1=0.01θ0=0.01(6.4286)=0.064286=0.01θ1=0.01(23.289)=0.23289

    终止迭代判断:两个 θ \theta θ梯度下降的距离都大于设定的阈值 ε \varepsilon ε,继续迭代。
∣ d 0 ∣ = 0.064286 > ε = 0.001 & ∣ d 2 ∣ = 0.23289 > ε = 0.001 \begin{aligned} |d0| = 0.064286 & > \varepsilon =0.001\\ & \& \\ |d2| = 0.23289 & > \varepsilon =0.001\\ \end{aligned} d0=0.064286d2=0.23289>ε=0.001&>ε=0.001

迭代第2次,计算出:
    更新两个 θ \theta θ
θ 0 : = θ 0 − d 0 = 0.07 + 0.064286 = 0.134286 θ 1 : = θ 1 − d 1 = 0.25 + 0.23289 = 0.48289 \theta_{0} := \theta_{0} - d0 =0.07+0.064286 = 0.134286 \\ \theta_{1} := \theta_{1} - d1 = 0.25+0.23289 = 0.48289 θ0:=θ0d0=0.07+0.064286=0.134286θ1:=θ1d1=0.25+0.23289=0.48289

......暂且撸到这里😄

2.2 python 实现

2.2.1 代数形式

import numpy as np

def GetH_Y(x,y,Theta):
    '''
        功能:获取损失函数梯度表达式的部分:h-y
        传入:X        --> 特征,如单特征2个样本为 [[1, 1], [1, 2]],其中x0==1
             Y        --> 对应的样本输出
             Theta    --> 模型参数
        返回:
            表达式部分:h-y 
        
    '''
    m = len(x) # m个特征,包含x0==1这个特征
    res = "+".join(['Theta[{}]*x[{}]'.format(i,i) for i in range(m)])
    
    return eval('({}) - y'.format(res))

def GetDistanceAndTheta(X,Y,Alpha,Theta):
    '''
        功能:获取梯度下降的距离和迭代更新后的theta
        传入:X       --> 特征,如单特征2个样本为 [[1, 1], [1, 2]],其中x0==1
             Y       --> 对应的样本输出
             Theta   --> 模型参数
             Alpha   --> 步长
        返回:
            distance --> 梯度下降的距离
            Theta    --> 更新后的theta
    '''
    m = len(X[0]) # m个特征,包含x0==1这个特征
    n = len(X)    # n个样本
    distance = [] # 梯度下降距离
    for i in range(m):
        nabla = 1/n * np.sum([GetH_Y(x,y,Theta)*x[i] for x,y in zip(X,Y)]) # theta对应的损失函数梯度
        distance.append(nabla*Alpha)                                       # 梯度下降距离
    
    print("   theta: ",Theta)    # 打印目前的theta
    print("distance: ",distance) # 打印梯度下降距离
    print("---------")
    
    Theta = list(map(lambda x: x[0]-x[1], zip(Theta, distance))) # 更新 theta
    
    return distance,Theta
    
    
def GradientDescent(X,Y,Theta,Alpha,Epsilon,Freq):
    '''
        功能:使用梯度下降法计算线性函数的参数近似值(代数法)
        传入:X        --> 特征,如单特征2个样本为 [[1, 1], [1, 2]],其中x0==1
             Y        --> 对应的样本输出
             Theta    --> 模型参数
             Alpha    --> 步长
             Freq     --> 迭代次数
             Epsilon  --> 终止迭代的阈值
        返回:
        
    '''
    print("迭代第%s次"%Freq)
    distance,Theta = GetDistanceAndTheta(X,Y,Alpha,Theta) # 开始迭代
    AbsDistance = list(map(lambda x:abs(x),distance))     # 取梯度下降距离的绝对值
    
    # 判断任何一个theta的梯度下降距离是否大于给定的阈值,如果为True,则继续迭代,否则终止迭代.
    while (np.array(AbsDistance) > Epsilon).any():
        Freq += 1                                             # 迭代次数加 1
        print("迭代第%s次"%Freq)                               # 打印迭代次数
        distance,Theta = GetDistanceAndTheta(X,Y,Alpha,Theta) # 继续迭代
        AbsDistance = list(map(lambda x:abs(x),distance))     # 取梯度下降距离的绝对值
    
    print("迭代终止!")
    
if __name__ == "__main__":
    x = [[1,1], [1,2], [1,3], [1,4], [1,5]] # 其中x0==1
    y = [3, 5, 7, 9, 11]
    
    freq    = 0      # 迭代次数初始化为0
    theta   = [0,0]  # 参数初始化
    alpha   = 0.01   # 步长
    epsilon = 0.0001 # 迭代终止条件的阈值
    GradientDescent(x,y,theta,alpha,epsilon,freq)    

在这里插入图片描述
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........................................................................ ........................................................................
在这里插入图片描述
  不难看出,前几次迭代的结果与上文手撸版一致(结果可能存在小数点差异);最终的 θ \theta θ值也很接近最优解 θ 0 = 1 , θ 1 = 2 \theta_{0}=1,\theta_{1}=2 θ0=1,θ1=2
  上文计算 θ \theta θ的损失函数梯度时加了 1 n \frac{1}{n} n1,其实加和不加对对结果影响不大。比如将程序中的代码去掉 1 n \frac{1}{n} n1
在这里插入图片描述
改为
在这里插入图片描述
运行结果
在这里插入图片描述
  最终迭代了419次(加 1 n \frac{1}{n} n1迭代了1151次),只是迭代次数减少了(针对本案例而言),但结果是相差不大的。

2.2.2 矩阵形式

import numpy as np

def GetDistanceAndTheta(X,Y,Alpha,Theta):
    '''
        功能:获取梯度下降的距离和迭代更新后的theta
        传入:X       --> 特征,如单特征2个样本为 [[1, 1], [1, 2]],其中x0==1
             Y       --> 对应的样本输出
             Theta   --> 模型参数
             Alpha   --> 步长
        返回:
             D       --> 梯度下降的距离
             Theta   --> 更新后的theta
    '''
    D = np.dot(Alpha*np.array(X).T,np.dot(X,Theta)-Y)

    print("   Theta: ",Theta)  # 打印目前的theta
    print("Distance: ",D)      # 打印梯度下降距离
    print("---------")
    
    Theta -= D # 更新 theta
    
    return D,Theta
    
    
def GradientDescent(X,Y,Theta,Alpha,Epsilon,Freq):
    '''
        功能:使用梯度下降法计算线性函数的参数近似值(代数法)
        传入:X        --> 特征,如单特征2个样本为 [[1, 1], [1, 2]],其中x0==1
             Y        --> 对应的样本输出
             Theta    --> 模型参数
             Alpha    --> 步长
             Freq     --> 迭代次数
             Epsilon  --> 终止迭代的阈值
        返回:
        
    '''
    print("迭代第%s次"%Freq)
    D,Theta = GetDistanceAndTheta(X,Y,Alpha,Theta) # 迭代第0次
    AbsD = list(map(lambda x:abs(x),D))            # 取梯度下降距离的绝对值
    
    # 判断任何一个theta的梯度下降距离是否大于给定的阈值,如果为True,则继续迭代,否则终止迭代.
    while (np.array(AbsD) > Epsilon).any():
        Freq += 1                                      # 迭代次数加 1
        print("迭代第%s次"%Freq)                         # 打印迭代次数
        D,Theta = GetDistanceAndTheta(X,Y,Alpha,Theta) # 继续迭代
        AbsD = list(map(lambda x:abs(x),D))            # 取梯度下降距离的绝对值
        AbsD = list(map(lambda x:abs(x),D))            # 取梯度下降距离的绝对值
        
    print("迭代终止!")
    
if __name__ == "__main__":
    x = [[1,1], [1,2], [1,3], [1,4], [1,5]] # 其中x0==1
    y = [3, 5, 7, 9, 11]
    
    freq    = 0      # 迭代次数初始化为0
    theta   = [0,0]  # 参数初始化
    alpha   = 0.01   # 步长
    epsilon = 0.0001 # 迭代终止条件的阈值
    GradientDescent(x,y,theta,alpha,epsilon,freq)    

在这里插入图片描述
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ........................................................................ ........................................................................
在这里插入图片描述

  • 该结果与代数形式下不加 1 n \frac{1}{n} n1 的结果一致。
  • 矩阵形式的写法代码较为简洁、运行速度较快.

参考:梯度下降(Gradient Descent)小结

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值