《动手学深度学习》第三十一天---小批量随机梯度下降

小批量随机梯度下降:在更新每一参数时都使用一部分样本来进行更新。为了克服上面两种方法的缺点,又同时兼顾两种方法的优点。在这里插入图片描述
小批量随机梯度下降随机均匀采样一个由训练数据样本索引组成的小批量βt。我们可以通过重复采样(sampling with replacement)或者不重复采样(sampling without replacement)得到一个小批量中的各个样本。可以使用下列公式来计算时间步t的小批量βt上目标函数位于xt-1的梯度gt:
在这里插入图片描述
给定学习率 ηt (取正数),小批量随机梯度下降对自变量的迭代如下:
在这里插入图片描述
基于随机采样得到的梯度的方差在迭代过程中无法减小。因此在实际中,(小批量)随机梯度下降的学习率可以在迭代过程中自我衰减。

(一)读取数据

本章里我们将使用一个来自NASA的测试不同飞机机翼噪音的数据集来比较各个优化算法 [1]。我们使用该数据集的前1,500个样本和5个特征,并使用标准化对数据进行预处理。

import d2lzh as d2l
from mxnet import autograd, gluon, init, nd
from mxnet.gluon import nn, data as gdata, loss as gloss
import numpy as np
import time

def get_data_ch7():  
    data = np.genfromtxt('../data/airfoil_self_noise.dat', delimiter='\t') # 从文本文件加载数据
    data = (data - data.mean(axis=0)) / data.std(axis=0)
    # numpy.mean(axis=0)计算一列的均值,numpy.std(axis=0)计算一列的标准差
    return nd.array(data[:1500, :-1]), nd.array(data[:1500, -1])  # [:-1]读取倒数第一个元素之外的所有元素,[-1]读取倒数第一个元素

features, labels = get_data_ch7()

(二)从零开始实现

定义小批量随机梯度下降算法sgd

def sgd(params,states,hyperparams):  # 在字典hyperparams里添加了一个状态输入states
      for p in params:
            p[:] -= hyperparams['lr']*p.grad  # 由于训练函数里对各个小批量样本的损失求了平均,所以优化算法的梯度不需要除以批量大小

实现通用的训练函数train_ch7()

def train_ch7(trainer_fn,states,hyperparams,features,labels,batch_size=10,num_epochs=2):
     net,loss=d2l.linreg,d2l.squared_loss  # 线性回归,平方损失
     w=nd.random.normal(scale=0.01,shape=(features.shape[1],1))   # 初始化权重
     b=nd.zeros(1)  # 初始化偏差
     w.attach_grad()
     b.attach_grad()

     def eval_loss():  # 对损失求平均
          return loss(net(features,w,b),labels).mean().asscalar()

     ls = [eval_loss()]
     data_iter=gdata.DataLoader(gdata.ArrayDataset(features,labels),batch_size,shuffle=True)
     for _ in range(num_epochs):
          start=time.time()
          for batch_i,(X,y) in enumerate(data_iter):
                with autograd.record():
                      l = loss(net(X,w,b),y).mean()  # 使用平均误差
                l.backward()
                trainer_fn([w,b],states,hyperparams)  # 迭代模型参数
                if (batch_i+1) * batch_size % 100 == 0 :
                     ls.append(eval_loss())  # 每100个样本记录当前训练误差
      
     
     print('loss: %f,%f sec per epoch' % (ls[-1],time.time()-start))
     d2l.set_figsize()
     d2l.plt.plot(np.linspace(0,num_epochs,len(ls)),ls)
     d2l.plt.xlabel('epoch')
     d2l.plt.ylabel('loss')
     
def train_sgd(lr,batch_size,num_epochs=2):
      train_ch7(sgd,None,{'lr':lr},features,labels,batch_size,num_epochs)

train_sgd(1,1500,6)  # 每次迭代数目是总量,代表使用的是梯度下降,训练周期是6

在这里插入图片描述

train_sgd(0.005,1)  # 当批量大小为1时,优化使用的时随机梯度下降。每次迭代只采用一个样本,所以每个周期需要1500次迭代

在这里插入图片描述

train_sgd(0.05,10)  # 每次迭代的批量大小为10,小批量随机梯度下降

在这里插入图片描述

(三)简洁实现

def train_gluon_ch7(trainer_name,trainer_hyperparams,features,labels,batch_size=10,num_epochs=2):
      net = nn.Sequential()
      net.add(nn.Dense(1))
      net.initialize(init.Normal(sigma=0.01))
      loss=gloss.L2Loss()
      def eval_loss():
           return loss(net(features),labels).mean().asscalar()
      ls=[eval_loss()]
      data_iter=gdata.DataLoader(gdata.ArrayDataset(features,labels),batch_size,shuffle=True)
      trainer=gluon.Trainer(net.collect_params(),trainer_name,trainer_hyperparams)
      # 在Gluon里可以通过创建Trainer实例来调用优化算法。
      for _ in range (num_epochs):
            start = time.time()
            for batch_i,(X,y) in enumerate(data_iter):
                 with autograd.record():
                       l=loss(net(X),y)
                 l.backward()
                 trainer.step(batch_size)
                 if (batch+i +1) * batch_size % 100 == 0:
                     ls.append(eval_loss())
      print('loss: %f,%f sec per epoch' % (ls[-1],time.time() - start))
      d2l.set_figsize()
      d2l.plt.plot(np.linspace(0,num_epochs,len(ls)),ls)
      d2l.plt.xlabel('epoch')
      d2l.plt.ylabel('loss')


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值