机器学习中常用的梯度下降法

写在前面

最近在上机器学习的讨论班,今天讲到梯度下降法,又去翻看了吴恩达老师机器学习课程的相关视频,记录下学习笔记。

梯度下降算法就可以用爬山去解释的非常典型的一个例子。 设想,我们现在在一座风景优美的山上,天快黑了,我们该怎样选择下山路径,以最快的速度下山到山脚下。我们站在所在的位置往四周看,发现有一个方向最陡(负梯度方向),沿着这个方向走一步,能让我们的海拔降低最多,所以我们就沿着这个方向走一步。 然后在现在站的位置上,再看四周,找一个最陡的方向走一步,以此一步一步往山下走。这样我们能以最快的速度到达山脚(局部最小解)。这就是梯度下降法的思想。

梯度下降算法

看了一些资料,现在在机器学习方向,常用梯度下降法有三种形式:批量梯度下降法(Batch Gradient Descent),随机梯度下降法(Stochastic Gradient Descent),小批量梯度下降法(Mini-Batch Gradient Descent)。我们以线性回归的目标函数为例来分别讲解下三种形式的梯度下降方法。设有数据集 D = { ( x i , y i ) , i = 1 , 2 , ⋯   , m } D=\{(x_i,y_i),i=1,2,\cdots,m\} D={(xi,yi),i=1,2,,m}, 其中 x i = ( x i ( 1 ) , x i ( 2 ) , ⋯   , x i ( d ) ) T , y i ∈ R x_i=(x^{(1)}_i,x^{(2)}_i,\cdots,x^{(d)}_i)^T, y_i\in \mathbb{R} xi=(xi(1),xi(2),,xi(d))T,yiR, 要求解以下最小化误差函数

θ ∗ = arg ⁡ min ⁡ J ( θ ) \theta^*=\arg \min J(\theta) θ=argminJ(θ)
其中
J ( θ ) = 1 2 m ∑ i = 1 m ( θ T x i − y i ) 2 J(\theta)=\frac{1}{2m}\sum^m_{i=1}\left(\theta^Tx_i-y_i\right)^2 J(θ)=2m1i=1m(θTxiyi)2

1.批量梯度下降法(BGD)

J ( θ ) J(\theta) J(θ)的梯度为
∇ J ( θ ) = 1 m ∑ i = 1 m ( θ T x i − y i ) x i \nabla J(\theta)=\frac{1}{m}\sum^m_{i=1}(\theta^{T}x_i-y_i)x_i J(θ)=m1i=1m(θTxiyi)xi选择合适的步长 η \eta η,可以得到BGD如下:

BGD算法
Step1:选择合适的初始值 θ 0 \theta_0 θ0和误差容忍度 ϵ \epsilon ϵ,学习率 η \eta η
Step2:对 k = 1 , 2 , ⋯ k=1,2,\cdots k=1,2,
θ k + 1 = θ k + η m ∑ i = 1 m ( y i − θ T x i ) x i \hskip3em\theta_{k+1}=\theta_k+\frac{\eta}{m}\sum^m_{i=1}(y_i-\theta^{T}x_i)x_i θk+1=θk+mηi=1m(yiθTxi)xi
\hskip3em 如果 ∣ J ( θ k + 1 ) − J ( θ k ) ∣ < ϵ |J(\theta_{k+1})-J(\theta_k)| < \epsilon J(θk+1)J(θk)<ϵ, 停止迭代
Step3:输出 θ k + 1 \theta_{k+1} θk+1为所求最小值点。

2.随机梯度下降法(SGD)

用批量梯度下降法每次更新参数 θ \theta θ的时候,需要对所有的训练样本进行求和,当训练数据量很大的时候,计算量会非常大。 为了解决这个困难,随机梯度下降法被提出。 SGD的基本思路是,先将训练样本随机打乱重新排好,然后每次更新参数 θ \theta θ时,依次选取其中的一个样本,使其误差函数下降。第 k k k个样本的误差函数

J k ( θ ) = 1 2 ( θ T x i − y i ) 2 J_k(\theta)=\frac{1}{2}\left(\theta^Tx_i-y_i\right)^2 Jk(θ)=21(θTxiyi)2
梯度为 ∇ J k ( θ ) = ( θ T x i − y i ) x i \nabla J_k(\theta)=(\theta^{T}x_i-y_i)x_i Jk(θ)=(θTxiyi)xi。选择合适的步长 η \eta η,可以得到SGD如下:

SGD算法
Step1:选择合适的初始值 θ 0 \theta_0 θ0和误差容忍度 ϵ \epsilon ϵ,学习率 η \eta η
Step2:将训练样本 ( x i , y i ) , i = 12 , ⋯   , m (x_i,y_i),i=12,\cdots,m (xi,yi),i=12,,m,打乱重新排序。打乱之后的训练样本仍记为 ( x i , y i ) , i = 12 , ⋯   , m (x_i,y_i),i=12,\cdots,m (xi,yi),i=12,,m
Step3:do{ //一般重复10次左右
\hskip4em for i = 1 , 2 , ⋯   , m i=1,2,\cdots, m i=1,2,,m,
\hskip5em θ k + 1 = θ k + η ( y i − θ T x i ) x i \theta_{k+1}=\theta_k+\eta(y_i-\theta^{T}x_i)x_i θk+1=θk+η(yiθTxi)xi
\hskip4em 如果 ∣ J ( θ k + 1 ) − J ( θ k ) ∣ < ϵ |J(\theta_{k+1})-J(\theta_k)| < \epsilon J(θk+1)J(θk)<ϵ, 停止迭代
\hskip3em }
Step4:输出 θ k + 1 \theta_{k+1} θk+1为所求最小值点。

3.小批量梯度下降法(MGD)

结合BGD和SGD算法,产生了小批量梯度下降法,其思路为:选取适当的batchsize,利用训练样本中batchsize个样本来更新参数 θ \theta θ,即每次更新参数 θ \theta θ时,使batchsize个样本的误差下降。

MGD算法
Step1:选择合适的初始值 θ 0 \theta_0 θ0和误差容忍度 ϵ \epsilon ϵ,学习率 η \eta η和batchsize, 令 n b = M b s nb=\frac{M}{bs} nb=bsM, t = 0 t=0 t=0
Step2:for j = 1 , 2 , ⋯   , n b j=1,2,\cdots, nb j=1,2,,nb
\hskip4em θ k + 1 = θ k + η b s ∑ i = t t + b s ( y i − θ T x i ) x i \theta_{k+1}=\theta_k+\frac{\eta}{bs}\sum^{t+bs}_{i=t}(y_i-\theta^{T}x_i)x_i θk+1=θk+bsηi=tt+bs(yiθTxi)xi
\hskip4em t=t+bs
\hskip4em 如果 ∣ J ( θ k + 1 ) − J ( θ k ) ∣ < ϵ |J(\theta_{k+1})-J(\theta_k)| < \epsilon J(θk+1)J(θk)<ϵ, 停止迭代
Step4:输出 θ k + 1 \theta_{k+1} θk+1为所求最小值点。

算例

由于熬夜感冒了,先实现BGD。给定数据集如图所示,对这组数据做线性回归。

在这里插入图片描述
线性回归所得为下图红色直线在这里插入图片描述

代码实现:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

def getData():
    fpath=r'E:\\Li\\python\\database\\data_linear.csv'
    data=pd.read_csv(fpath,header=None,names=['x','y'])
    x = np.array(data.x)
    y = np.array(data.y)
    return x,y

def loss(x,y,w):
    m = x.shape[0]
    v=y-np.dot(x,w)
    return np.dot(v.T,v)/(2*m)

def BGD(x, y, step_size=0.0001, max_iter_count=10000, tol = 1e-6):
    m = x.shape[0]
    d = (len(x.shape)>1 and [x.shape[1]] or [1])[0]    
    x = np.concatenate(([x], [np.ones(m)]), axis=0).T
    w = np.ones((x.shape[1],))
    J0 = loss(x,y,w)
    n_iter = 0
    while  n_iter < max_iter_count:
        n_iter += 1
        c = y - np.dot(x,w)
        vtmp = np.zeros((d+1,m))
        for i in range(m):
            vtmp[:,i] = c[i] * x[i,:]
        dw = np.sum(vtmp,axis=1)
        dw = step_size * dw /m
        w += dw
        J1 = loss(x,y,w)
        if abs(J1-J0) < tol: break
        J0 = J1
    return w,n_iter

if __name__ == '__main__':
    x, y = getData()
    plt.scatter(x,y)
    w,n_iter=BGD(x,y)
    x1 = np.linspace(min(x),max(x), 100)
    x2 = np.ones((100,))
    xi = np.concatenate(([x1], [x2]), axis=0).T
    yi = np.dot(xi, w)
    plt.plot(x1,yi,'r-')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值