《动手学深度学习》第三十天---梯度下降和随机梯度下降

(一)一维梯度下降

首先看一段代码:

%matplotlib inline
import d2lzh as d2l
import math
from mxnet import nd
import numpy as np

def gd(eta):
    x = 10
    results = [x]
    for i in range(10):
        x -= eta * 2 * x  # f(x) = x * x的导数为f'(x) = 2 * x
        results.append(x)
    print('epoch 10, x:', x)
    return results

我们可以看出上述代码实现了通过
在这里插入图片描述
来迭代x,其中η=0.2,f(x) = x * x,x初始值为10,一共迭代了十次最后得到x=0.06。

这个过程有什么意义呢?根据泰勒展开公式我们知道:
在这里插入图片描述
这里?′(?)是函数?在?处的梯度。一维函数的梯度是一个标量,也称导数。接下来,找到一个常数?>0,使得||??′(?)||足够小,那么可以将?替换为−??′(?)并得到。
在这里插入图片描述
如果导数?′(?)≠0,那么??′(?)^2>0,所以
在这里插入图片描述这样得到的就是
我们通过选取一个初始值x和常数η>0,然后不断通过迭代x达到停止条件(条件自己可以设置,比如?′(?)^2的值已足够小,或者设置迭代次数)。

设置追踪迭代轨迹的函数show_trace():

def show_trace(res):
    n=max(abs(min(res)),abs(max(res)),10)  # abs(x)表示取绝对值
    f_line=np.arange(-n,n,0.1)
    d2l.set_figsize()
    d2l.plt.plot(f_line,[x*x for x in f_line])  # plt.plot(x,y,format_string,**kwargs),x轴数据,y轴数据,format_string控制曲线的格式字串 
    d2l.plt.plot(res,[x*x for x in res],'-o') # -o 表示实心圈标记
    d2l.plt.xlabel('x')
    d2l.plt.ylabel('f(x)')

在这里插入图片描述

(二)学习率

上述梯度下降算法中的正数 ? 通常叫作学习率。这是一个超参数,需要人工设定。

  1. 如果使用过小的学习率,会导致 ? 更新缓慢从而需要更多的迭代才能得到较好的解。
  2. 如果使用过大的学习率,||??′(?)|| 可能会过大从而使前面提到的一阶泰勒展开公式不再成立:这时我们无法保证迭代 ? 会降低?(?) 的值
    在这里插入图片描述

(三)多维梯度下降

同样先看一段代码:
zip和*zip的用法

def train_2d(trainer):   # 用来记录所有迭代的轨迹过程
    x1,x2,s1,s2 = -5,-2,0,0   # s1和s2是自变量状态
    results=[(x1,x2)]
    for i in range(20):
        x1,x2,s1,s2 = trainer(x1,x2,s1,s2)
        results.append((x1,x2))
        print('epoch %d,x1 %f,x2 %f' % (i+1,x1,x2))
        return results

def show_trace_2d(f,results):  #绘制迭代轨迹
    d2l.plt.plot(*zip(*results),'-o',color='#ff7f0e')
     # *zip()函数是zip()函数的逆过程,将zip对象变成原先组合前的数据
    x1,x2 = np.meshgrid(np.arange(-5.5,1.0,0.1),np.arange(-3.0,1.0,0.1))
    # np.meshgrid(*xi, **kwargs) 从坐标向量中返回坐标矩阵 ,例如X轴可以取三个值1,2,3,  Y轴可以取两个值7,8, 就可以获得6个点的坐标。
    d2l.plt.contour(x1,x2,f(x1,x2),color='#1f77b4')  # 绘制等高线
    d2l.plt.xlabel('x1')
    d2l.plt.ylabel('x2')
    
eta = 0.1  # 学习率0.1

def f_2d(x1,x2):  # 定义原函数
    return x1 ** 2 + 2 * x2 ** 2
    
def gd_2d(x1,x2,s1,s2):  # 定义梯度
    return (x1 - eta * 2 * x1,x2- eta * 4 * x2,0,0)
    
show_trace_2d(f_2d,train_2d(gd_2d))   # 绘制图像

在这里插入图片描述

上述过程是构造了一个输入的二维向量?=[?1,?2]⊤和输出为标量的目标函数?(?)=?1^2
+2*?2^2。那么,梯度∇?(?)=[2?1,4?2]⊤。我们将观察梯度下降从初始位置[-5,-2]开始对自变量x的迭代轨迹,一共迭代二十次,学习率为0.1。

对于一个d维向量:
在这里插入图片描述
目标函数有关x的梯度是一个由d个偏导数组成的向量:
在这里插入图片描述
方向导数D??(?)给出了?在?上沿着所有可能方向的变化率,可以表示为:
在这里插入图片描述
为了最小化f,我们希望找到f能被降低最快的方向,也就可以通过最小化方向导数来得到,而当?在梯度方向∇?(?)的相反方向时,方向导数D??(?)被最小化,f也就不断被降低。
因此可以通过:
在这里插入图片描述
得到最小的f。

(四)随机梯度下降

在深度学习里,目标函数通常是训练数据集中有关各个样本的损失函数的平均。设??(?)是有关索引为 ? 的训练数据样本的损失函数,?是训练数据样本数,?是模型的参数向量,那么目标函数定义为
在这里插入图片描述
目标函数在x处的梯度计算为:
在这里插入图片描述
如果使用梯度计算,当训练样本数很大时,梯度下降每次迭代的计算开销都很高。

随机梯度下降在每次迭代中,随即均匀采样的样本索引来计算随机梯度∇??(?),进而迭代x:
在这里插入图片描述
值得强调的是,随机梯度∇??(?)是对梯度∇?(?)的无偏估计。这意味,随机梯度是对梯度的一个良好的估计。

def sgd_2d(x1,x2,s1,s2):
    return (x1-eta*(2*x1+np.random.normal(0.1)),
           x2-eta*(4*x2+np.random.normal(0.1)),0,0)  
           # 通过在梯度中添加均值为0的随机噪声来模拟随机梯度下降
show_trace_2d(f_2d,train_2d(sgd_2d))

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值