SGD,Adam,AdamW,LAMB优化器

这篇具有很好参考价值的文章主要介绍了SGD,Adam,AdamW,LAMB优化器。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一. SGD,Adam,AdamW,LAMB优化器

优化器是用来更新和计算影响模型训练和模型输出的网络参数,使其逼近或达到最优值,从而最小化(或最大化)损失函数。

1. SGD

随机梯度下降是最简单的优化器,它采用了简单的梯度下降法,只更新每一步的梯度,但是它的收敛速度会受到学习率的影响。
优点: 简单性,在优化算法中没有太多的参数需要调整,通过少量的计算量就可以获得比较好的结果。
缺点: 在某些极端情况下容易受到局部最小值的影响,也容易出现收敛的问题。

1. Adam

解决 GD 中固定学习率带来的不同参数间收敛速度不一致的弊端,AdaGrad 和 RMSprop 诞生出来,为每个参数赋予独立的学习率。计算梯度后,梯度较大的参数获得的学习率较低,反之亦然。此外,为避免每次梯度更新时都独立计算梯度,导致梯度方向持续变化,Momentum 将上一轮梯度值加入到当前梯度的计算中,通过某种权重对两者加权求和,获得当前批次参数更新的梯度值。 Adam 结合了这两项考虑,既为每一个浮点参数自适应性地设置学习率,又将过去的梯度历史纳入考量,其实现原理如下:
SGD,Adam,AdamW,LAMB优化器

计算一阶、二阶动量矩,加入偏置修正,最后更新参数,gt表示t时刻梯度。从上述公式可以看出,训练前期的学习率和梯度更新是比较激进的,到后期逐渐平稳。虽然 Adam 优化器的使用会导致内存中多出两倍于原参数体量的占用,但与之换来的训练收益使得学术界并没有放弃这一高效的方法。

代码实现比较简单,照着公式敲就行了:

import autograd.numpy as np
from autograd import grad


class Adam:
    def __init__(self, loss, weights, lr=0.001, beta1=0.9, beta2=0.999, epislon=1e-8):
        self.loss = loss
        self.theta = weights
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.epislon = epislon
        self.get_gradient = grad(loss)
        self.m = 0
        self.v = 0
        self.t = 0

    def minimize_raw(self):
        self.t += 1
        g = self.get_gradient(self.loss)
        self.m = self.beta1 * self.m + (1 - self.beta1) * g
        self.v = self.beta2 * self.v + (1 - self.beta2) * (g * g)
        self.m_hat = self.m / (1 - self.beta1 ** self.t)
        self.v_hat = self.v / (1 - self.beta2 ** self.t)
        self.theta = self.theta - self.lr * self.m_hat / (self.v_hat ** 0.5 + self.epislon)
2. AdamW

Adam 虽然收敛速度快,但没能解决参数过拟合的问题。学术界讨论了诸多方案,其中包括在损失函数中引入参数的 L2 正则项。这样的方法在其他的优化器中或许有效,但会因为 Adam 中自适应学习率的存在而对使用 Adam 优化器的模型失效,具体分析可见fastai的这篇文章:AdamW and Super-convergence is now the fastest way to train neural nets。AdamW 的出现便是为了解决这一问题,达到同样使参数接近于 0 的目的。具体的举措,是在最终的参数更新时引入参数自身
SGD,Adam,AdamW,LAMB优化器

λ 即为权重衰减因子,常见的设置为 0.005/0.01。这一优化策略目前正广泛应用于各大预训练语言模型。

代码实现:

class AdamW:
    def __init__(self, loss, weights, lambda1, lr=0.001, beta1=0.9, beta2=0.999, epislon=1e-8):
        self.loss = loss
        self.theta = weights
        self.lr = lr
        self.beta1 = beta1
        self.beta2 = beta2
        self.epislon = epislon
        self.lambda1 = lambda1
        self.get_gradient = grad(loss)
        self.m = 0
        self.v = 0
        self.t = 0

    def minimize_raw(self):
        self.t += 1
        g = self.get_gradient(self.loss)
        self.m = self.beta1 * self.m + (1 - self.beta1) * g
        self.v = self.beta2 * self.v + (1 - self.beta2) * (g * g)
        self.m_hat = self.m / (1 - self.beta1 ** self.t)
        self.v_hat = self.v / (1 - self.beta2 ** self.t)
        self.theta = self.theta - self.lr * (
                    self.m_hat / (self.v_hat ** 0.5 + self.epislon) + self.lambda1 * self.theta)
3. LAMB

LAMB 优化器是 2019 年出现的一匹新秀,它将bert模型的预训练时间从3天压缩到了76分钟! LAMB 出现的目的是加速预训练进程,这个优化器也成为 NLP 社区为泛机器学习领域做出的一大贡献。在使用 Adam 和 AdamW 等优化器时,一大问题在于 batch size 存在一定的隐式上限,一旦突破这个上限,梯度更新极端的取值会导致自适应学习率调整后极为困难的收敛,从而无法享受增加的 batch size 带来的提速增益。LAMB 优化器的作用便在于使模型在进行大批量数据训练时,能够维持梯度更新的精度。具体来说,LAMB 优化器支持自适应元素级更新(adaptive element-wise updating)和准确的逐层修正(layer-wise correction)。LAMB 可将 BERT 预训练的批量大小扩展到 64K,且不会造成准确率损失。BERT 预训练包括两个阶段:1)前 9/10 的训练 epoch 使用 128 的序列长度,2)最后 1/10 的训练 epoch 使用 512 的序列长度。LAMB的算法如下:
SGD,Adam,AdamW,LAMB优化器

其中, ϕ 是一个可选择的映射函数,一种是 ϕ ( z ) = z ,另一种则为起到归一化作用的 m i n ( m a x ( z , γ l ) , γ u ) 。 γ l , γ u \phi 是 一 个 可 选 择 的 映 射 函 数 ,一种是\phi(z)=z, 另一种则为起到归一化作用的min(max(z,\gamma_l),\gamma_u)。 \gamma_l,\gamma_u ϕ是一个可选择的映射函数,一种是ϕ(z)=z,另一种则为起到归一化作用的min(max(z,γl),γu)γl,γu为预先设定的超参数,分别代表参数调整的下界和上界。这一简单的调整所带来的实际效果非常显著。使用 AdamW 时,batch size 超过 512 便会导致模型效果大幅下降,但在 LAMB 下,batch size 可以直接提到 32,000 而不会导致精度损失

以下是 LAMB 优化器的 tensorflow1.x 代码,可作为参考以理解算法:文章来源地址https://www.toymoban.com/news/detail-415476.html

class LAMBOptimizer(tf.train.Optimizer):
    '''
    LAMBOptimizer optimizer.
	
	# Important Note
		- This is NOT an official implementation.
		- LAMB optimizer is changed from arXiv v1 ~ v3.
		- We implement v3 version (which is the latest version on June, 2019.).
		- Our implementation is based on `AdamWeightDecayOptimizer` in BERT (provided by Google).
    # References
		- LAMB optimier: https://github.com/ymcui/LAMB_Optimizer_TF
		- Large Batch Optimization for Deep Learning: Training BERT in 76 minutes. https://arxiv.org/abs/1904.00962v3
		- BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. https://arxiv.org/abs/1810.04805
    # Parameters
		- There is nothing special, just the same as `AdamWeightDecayOptimizer`.
    '''
    def __init__(self,
                 learning_rate,
                 weight_decay_rate=0.01,
                 beta_1=0.9,
                 beta_2=0.999,
                 epsilon=1e-6,
                 exclude_from_weight_decay=None,
                 name="LAMBOptimizer"):
        """Constructs a LAMBOptimizer."""
        super(LAMBOptimizer, self).__init__(False, name)

        self.learning_rate = learning_rate
        self.weight_decay_rate = weight_decay_rate
        self.beta_1 = beta_1
        self.beta_2 = beta_2
        self.epsilon = epsilon
        self.exclude_from_weight_decay = exclude_from_weight_decay

    def apply_gradients(self, grads_and_vars, global_step=None, name=None):
        """See base class."""
        assignments = []
        for (grad, param) in grads_and_vars:
            if grad is None or param is None:
                continue

            param_name = self._get_variable_name(param.name)

            m = tf.get_variable(
                name=param_name + "/lamb_m",
                shape=param.shape.as_list(),
                dtype=tf.float32,
                trainable=False,
                initializer=tf.zeros_initializer())
            v = tf.get_variable(
                name=param_name + "/lamb_v",
                shape=param.shape.as_list(),
                dtype=tf.float32,
                trainable=False,
                initializer=tf.zeros_initializer())

            # Standard Adam update.
            next_m = (
                    tf.multiply(self.beta_1, m) + tf.multiply(1.0 - self.beta_1, grad))
            next_v = (
                    tf.multiply(self.beta_2, v) + tf.multiply(1.0 - self.beta_2,
                                                              tf.square(grad)))

            update = next_m / (tf.sqrt(next_v) + self.epsilon)

            # Just adding the square of the weights to the loss function is *not*
            # the correct way of using L2 regularization/weight decay with Adam,
            # since that will interact with the m and v parameters in strange ways.
            #
            # Instead we want ot decay the weights in a manner that doesn't interact
            # with the m/v parameters. This is equivalent to adding the square
            # of the weights to the loss with plain (non-momentum) SGD.
            if self._do_use_weight_decay(param_name):
                update += self.weight_decay_rate * param

            ############## BELOW ARE THE SPECIFIC PARTS FOR LAMB ##############

            # Note: Here are two choices for scaling function \phi(z)
            # minmax:   \phi(z) = min(max(z, \gamma_l), \gamma_u)
            # identity: \phi(z) = z
            # The authors does not mention what is \gamma_l and \gamma_u
            # UPDATE: after asking authors, they provide me the code below.
            # ratio = array_ops.where(math_ops.greater(w_norm, 0), array_ops.where(
            #      math_ops.greater(g_norm, 0), (w_norm / g_norm), 1.0), 1.0)

            r1 = tf.sqrt(tf.reduce_sum(tf.square(param)))
            r2 = tf.sqrt(tf.reduce_sum(tf.square(update)))

            r = tf.where(tf.greater(r1, 0.0),
                         tf.where(tf.greater(r2, 0.0),
                                  r1 / r2,
                                  1.0),
                         1.0)

            eta = self.learning_rate * r

            update_with_lr = eta * update

            next_param = param - update_with_lr

            assignments.extend(
                [param.assign(next_param),
                 m.assign(next_m),
                 v.assign(next_v)])
        return tf.group(*assignments, name=name)

    def _do_use_weight_decay(self, param_name):
        """Whether to use L2 weight decay for `param_name`."""
        if not self.weight_decay_rate:
            return False
        if self.exclude_from_weight_decay:
            for r in self.exclude_from_weight_decay:
                if re.search(r, param_name) is not None:
                    return False
        return True

    def _get_variable_name(self, param_name):
        """Get the variable name from the tensor name."""
        m = re.match("^(.*):\\d+$", param_name)
        if m is not None:
            param_name = m.group(1)
        return param_name

二. 参考链接

  1. Adam,AdamW,LAMB优化器原理与代码
  2. 优化器SGD、Adam和AdamW的区别和联系

到了这里,关于SGD,Adam,AdamW,LAMB优化器的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SGD算法的优化特性及其在深度学习中的应用(OptimizationPropertiesandApplicat

    作者:禅与计算机程序设计艺术 SGD(Stochastic Gradient Descent)算法作为深度学习中最常用的优化算法之一,具有较好的全局收敛速度和稳定性。然而,在某些场景下,SGD算法的训练效率和泛化能力仍有待提高。本文将探讨SGD算法的优化特性及其在深度学习中的应用。 引言 1.1

    2024年02月09日
    浏览(31)
  • Adam优化器及其变种的原理

    本文将从SGD开始介绍Adam优化器的原理以及其变种的提出背景。 SGD(随机梯度下降法)是基于 最速梯度下降 法的原理,假设我们存在损失函数,其中是要学习参数,定义如下的优化路径 ,使得损失函数值最小。这是一个不断更新迭代参数的过程,其中表示其中某一更新步,

    2024年02月04日
    浏览(31)
  • Adam优化器算法详解及代码实现

    在介绍Adam算法之前,先谈谈Adam中两个关键的算法: 学习率调整(RMSprop 算法) 与 梯度估计修正 。 学习率是神经网络优化时的重要超参数。在标准的梯度下降法中,每个参数在每次迭代时都使用相同的学习率,但是学习率如果过大就不会收敛,如果过小则收敛速度太慢。

    2024年02月02日
    浏览(34)
  • 深度学习优化入门:Momentum、RMSProp 和 Adam

    目录 深度学习优化入门:Momentum、RMSProp 和 Adam 病态曲率 1牛顿法 2 Momentum:动量 3Adam   本文,我们讨论一个困扰神经网络训练的问题,病态曲率。 虽然局部极小值和鞍点会阻碍我们的训练,但病态曲率会减慢训练的速度,以至于从事机器学习的人可能会认为搜索已经收敛到一

    2024年02月11日
    浏览(28)
  • 利用Adam优化算法进行语音识别任务:提升模型准确率

    作者:禅与计算机程序设计艺术 语音识别是人工智能领域中的一个重要应用,近年来随着深度学习算法的快速发展,语音识别技术也取得了长足的进步。在语音识别任务中,训练模型需要大量的数据和计算资源,而且模型的准确性也是至关重要的。因此,如何提高模型的准确

    2024年02月09日
    浏览(31)
  • 神经网络基础-神经网络补充概念-49-adam优化算法

    Adam(Adaptive Moment Estimation)是一种优化算法,结合了动量梯度下降法和RMSProp的优点,用于在训练神经网络等深度学习模型时自适应地调整学习率。Adam算法在深度学习中广泛应用,通常能够加速收敛并提高模型性能。 Adam算法综合了动量(momentum)和均方梯度的移动平均(RMS

    2024年02月12日
    浏览(24)
  • 改善神经网络——优化算法(mini-batch、动量梯度下降法、Adam优化算法)

    优化算法可以使神经网络运行的更快,机器学习的应用是一个高度依赖经验的过程,伴随着大量迭代的过程,你需要训练诸多模型,才能找到合适的那一个,所以,优化算法能够帮助你快速训练模型。 其中一个难点在于,深度学习没有在大数据领域发挥最大的效果,我们可以

    2024年02月12日
    浏览(37)
  • SDG,ADAM,LookAhead,Lion等优化器的对比介绍

    本文将介绍了最先进的深度学习优化方法,帮助神经网络训练得更快,表现得更好。有很多个不同形式的优化器,这里我们只找最基础、最常用、最有效和最新的来介绍。 首先,让我们定义优化。当我们训练我们的模型以使其表现更好时,首先使用损失函数,训练时损失的减

    2023年04月09日
    浏览(29)
  • 【机器学习】P17 梯度下降 与 梯度下降优化算法(BGD 等 与 Adam Optimizer、AdaGrad、RMSProp)

    梯度下降(Gradient Descent)是一种常用的优化算法,用于求解目标函数的最小值。(在机器学习应用梯度下降中,主要目标是为了最小化损失函数); 其基本思想是通过不断迭代调整参数,使得目标函数的值不断逼近最小值。(机器学习中是为了最小化损失函数,即使得预测

    2023年04月16日
    浏览(35)
  • 涨点技巧: 谷歌强势推出优化器Lion,引入到Yolov8,内存更小、效率更高,秒杀Adam(W)

    论文:https://arxiv.org/abs/2302.06675 代码:automl/lion at master · google/automl · GitHub 1

    2023年04月18日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包