46.4_SGD以外的优化方法

46.4 SGD以外的优化方法

基于梯度的优化方法多种多样。比较有代表性的方法有Momentum、AdaGrad(参考文献[27])、AdaDelta(参考文献[28])和Adam(参考文献[29])等。引入Optimizer类是为了轻松切换这些不同的优化方法,这里我们通过继承基类Optimizer来实现其他优化方法。本节将实现Momentum这一优化方法。

AdaGrad、AdaDelta和Adam等优化方法的代码在dezero/optimizers.py中。本书不对这些方法进行讲解。感兴趣的读者请参考《深度学习入门:基于Python的理论与实现》的6.1节。

Momentum方法的式子如下所示。

vαvηLW(46.1)\boldsymbol {v} \leftarrow \alpha \boldsymbol {v} - \eta \frac {\partial L}{\partial \boldsymbol {W}} \tag {46.1}
WW+v(46.2)\boldsymbol {W} \leftarrow \boldsymbol {W} + \boldsymbol {v} \tag {46.2}

其中, W\pmb{W} 是需要更新的权重参数, LW\frac{\partial L}{\partial \pmb{W}} 是梯度(损失函数 LLW\pmb{W} 的梯度), η\eta 是学习率。另外, v\pmb{v} 相当于物理学中的速度。式子46.1表示这样一个物理法则:物体在梯度方向上受到一个力,这个力使物体加速。式子46.2表示物体以该速度移动位置(参数)。

式子46.1中有一个 αv\alpha \pmb{v} 。该项的作用是让物体在没有受任何力的作用时逐渐减速(可将 α\alpha 设置为0.9这样的值)。

Momentum的代码如下所示,类名为MomentumSGD。

dezero/optimizers.py

import numpy as np   
class MomentumSGD(Optimizer): def__init__(self,lr  $= 0.01$  ,momentum  $\equiv 0.9$  super().__init_(self.lr  $=$  lr self.momentum  $=$  momentum self.vs  $=$  {} defupdate_one(self,param): v_key  $=$  id(param) ifv_keynot in self.vs: self.vs[v_key]  $=$  np.zeros_like(param.data) v  $=$  self.vs[v_key] v  $\ast =$  self.momentum v  $= =$  self.lr \* param_grad.data param.data  $+ =$  v

上面的每个参数都拥有相当于速度的数据。因此,在上面的代码中字典的实例变量被设置为self.vs。vs在初始化时是空的,但当update_one()第一次被调用时,它会创建在形状上与参数相同的数据。之后,将式子46.1和式子46.2用代码实现即可。

dezero/optimizers.py中MomentumSGD类的代码与上面的代码有些不同。
dezero/optimizers.py中为了支持GPU,在np.ones_like方法之前根据数据类型调用了CuPy的copy.ones_like方法。步骤52中会实现对GPU的支持。

以上就是Momentum的代码。现在我们可以把之前实现的训练代码中的优化方法轻松切换到Momentum。只要将optimizer = SGD(lr)替换为optimizer = MomentumSGD(lr)即可,不需要进行其他任何修改。这样我们就可以轻松切换各种优化方法了。

步骤47

softmax函数和交叉熵误差

此前我们使用神经网络解决了回归问题,现在开始我们要挑战新的问题——多分类。顾名思义,多分类是将数据分类为多个值的问题。对未分类的对象,我们推断它属于哪一个类别。本步骤为进行多分类做准备,下一个步骤将使用DeZero实现多分类。