pytorch优化器

优化概念

神经网络的学习的目的是找到使损失函数的值尽可能小的参数。这是寻找最优参数的问题,解决这个问题的过程称为最优化(optimization)。
为了找到最优参数,我们将参数的梯度(导数)作为了线索。 使用参数的梯度,沿梯度方向更新参数,并重复这个步骤多次,从而逐渐靠 近最优参数,这个过程称为随机梯度下降法(stochastic gradient descent), 简称SGD。
在这里插入图片描述
W为需要更新的权重参数;损失函数关于W的梯度为W的偏导;η表示学习率,实际应用中会取0.01或0.001。

class SGD:    
    def __init__(self, lr=0.01):        
        self.lr = lr
    def update(self, params, grads):        
        for key in params.keys():            
            params[key] -= self.lr * grads[key]

进行初始化时的参数lr表示learning rate(学习率)。这个学习率会保存为实例变量。此外,代码段中还定义了update(params, grads)方法, 这个方法在SGD中会被反复调用。参数params和grads(与之前的神经网络 的实现一样)是字典型变量,按params[‘W1’]、grads[‘W1’]的形式,分别保 存了权重参数和它们的梯度。

Momentum

Momentum是“动量”的意思,和物理有关。用数学式表示Momentum方法,如下所示:

pytorch优化器_第1张图片
W表示要更新的权重参数,η表示学习率;变量v,对应物理上的速度。 式(6.3)表示了物体在梯度方向上受力,在这个力的作用下,物体的速度增加这一物理法则。如图6-4所示,Momentum方法给人的感觉就像是小球在 地面上滚动。

pytorch优化器_第2张图片
式(6.3)中αv项,在物体不受任何力时,该项承担使物体逐渐减 速的任务(α设定为0.9之类的值),对应物理上的地面摩擦或空气阻力。对应实现代码如下。


class Momentum:    
    def __init__(self, lr=0.01, momentum=0.9):        
        self.lr = lr        
        self.momentum = momentum        
        self.v = None
    def update(self, params, grads):        
        if self.v is None:            
            self.v = {}            
            for key, val in params.items():                
                self.v[key] = np.zeros_like(val)
        for key in params.keys():            
            self.v[key] = self.momentum*self.v[key] - self.lr*grads[key]            
            params[key] += self.v[key]
           

AdaGrad

在神经网络的学习中,学习率(数学式中记为η)的值很重要。学习率过小,会导致学习花费过多时间;反过来,学习率过大,则会导致学习发散而不能 正确进行。 在关于学习率的有效技巧中,有一种被称为学习率衰减(learning rate decay)的方法,即随着学习的进行,使学习率逐渐减小。实际上,一开始“多” 学,然后逐渐“少”学的方法,在神经网络的学习中经常被使用。 逐渐减小学习率的想法,相当于将“全体”参数的学习率值一起降低。 而AdaGrad进一步发展了这个想法,针对“一个一个”的参数,赋予其“定 制”的值。 AdaGrad会为参数的每个元素适当地调整学习率,与此同时进行学习 (AdaGrad的Ada来自英文单词Adaptive,即“适当的”的意思)。
pytorch优化器_第3张图片
AdaGrad会记录过去所有梯度的平方和。因此,学习越深入,更新 的幅度就越小。实际上,如果无止境地学习,更新量就会变为0, 完全不再更新。

class AdaGrad:    
	"""AdaGrad"""
    def __init__(self, lr=0.01):        
    self.lr = lr        
    self.h = None
    def update(self, params, grads):        
        if self.h is None:        
            self.h = {}        
            for key, val in params.items():            
                self.h[key] = np.zeros_like(val)
    for key in params.keys():        
        self.h[key] += grads[key] * grads[key]        
        params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)

RMSProp

AdaGrad会记录过去所有梯度的平方和。因此,学习越深入,更新 的幅度就越小。实际上,如果无止境地学习,更新量就会变为0, 完全不再更新。RMSProp方法在这一问题上进行了改进。RMSProp方法并不是将过去所有的梯度一视同仁地相加,而是逐渐地遗忘过去的梯度,在做加法运算时将新梯度的信息更多地反映出来。 这种操作从专业上讲,称为“指数移动平均”,呈指数函数式地减小过去的梯度的尺度。实现代码如下:

class RMSprop:
    """RMSprop"""
    def __init__(self, lr=0.01, decay_rate = 0.99):
        self.lr = lr
        self.decay_rate = decay_rate
        self.h = None       
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)           
        for key in params.keys():
            self.h[key] *= self.decay_rate
            self.h[key] += (1 - self.decay_rate) * grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)        

Adam

Adam是2015年提出的新方法。它的理论有些复杂,直观地讲,就是融合了Momentum和AdaGrad的方法。通过组合前面两个方法的优点,有望 实现参数空间的高效搜索。此外,进行超参数的“偏置校正”也是Adam的特征。

class Adam:
    """Adam"""
    def __init__(self, lr=0.001, beta1=0.9, beta2=0.999):
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.iter = 0
        self.m = None
        self.v = None        
    def update(self, params, grads):
        if self.m is None:
            self.m, self.v = {}, {}
            for key, val in params.items():
                self.m[key] = np.zeros_like(val)
                self.v[key] = np.zeros_like(val)        
        self.iter += 1
        lr_t  = self.lr * np.sqrt(1.0 - self.beta2**self.iter) / (1.0 - self.beta1**self.iter)                 
        for key in params.keys():
            self.m[key] += (1 - self.beta1) * (grads[key] - self.m[key])
            self.v[key] += (1 - self.beta2) * (grads[key]**2 - self.v[key])            
            params[key] -= lr_t * self.m[key] / (np.sqrt(self.v[key]) + 1e-7)  

参考:深度学习入门–基于python的理论与实现(Deep learning from scratch)

你可能感兴趣的:(Pytorch)