SGD,Adam,AdamW,LAMB优化器

news2024/11/23 7:58:45

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

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

1. SGD

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

1. Adam

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

计算一阶、二阶动量矩,加入偏置修正,最后更新参数,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 的目的。具体的举措,是在最终的参数更新时引入参数自身
AdamW

λ 即为权重衰减因子,常见的设置为 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的算法如下:
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 代码,可作为参考以理解算法:

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的区别和联系

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/417447.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt音视频开发37-识别鼠标按下像素坐标

一、前言 在和视频交互过程中,用户一般需要在显示视频的通道上点击对应的区域,弹出对应的操作按钮,将当前点击的区域或者绘制的多边形区域坐标或者坐标点集合,发送出去,通知其他设备进行处理。比如识别到很多人脸&…

使用 gzip 压缩数据

gzip 是GNU/Linux平台下常用的压缩软件,处理后缀名.gz的文件。 gzip 、 gunzip 和 zcat 都可以处理这种格式的。但这些工具只能压缩/解压缩单个文件或数据流,无法直接归档目录和多个文件。但是, gzip 可以同tar 和 cpio 这类归档工具配合使用…

JavaWeb——网络的基本概念

目录 一、IP地址 1、定义 2、格式 (1)、A类地址 (2)、B类地址 (3)、C类地址 (4)、特殊地址 二、端口号 三、协议 四、协议分层 1、定义 2、分类 (1&#xf…

pytorch进阶学习(六):如何对训练好的模型进行优化、验证并且对训练过程进行准确率、损失值等的可视化,新手友好超详细记录

课程资源: 7、模型验证与训练过程可视化【小学生都会的Pytorch】【提供源码】_哔哩哔哩_bilibili 推荐与上一节笔记搭配食用~: pytorch进阶学习(五):神经网络迁移学习应用的保姆级详细介绍,如何将训练好…

给boss直聘的搜索结果加上hr活跃状态,少看点半年活跃的岗位,有书签版,油猴版

背景:这段时间找工作,无奈大环境不好,所在城市大部分公司都投了。就是没几个回复的,要么送达,要么已读不回,要么拿了简历没见邀约。然后boss为了争取我们多浏览网站,把一些陈年老醋也拿上台面&a…

企业云盘如何实现文件共享?

企业文件共享的方式有很多,最常见的就是使用第三方企业云盘工具进行文件实时共享,这种方法不仅方便安全,而且兼容性高。 企业云盘主要是通过建立企业内部共享文件夹进行文件分享,支持通过权限管控来保障文件的安全,管理…

SonarQube踩坑:本地利用maven进行代码SonarQube静态扫描

1、ERROR: [1] bootstrap checks failed [1]: max virtual memory areas vm.max_map_count SonarQube内置ElasticSearch内存不够 - 解决办法:修改内存配置大小 - 查询当前配置内存:sysctl -a | grep vm.max_map_count - 更改内存大小:sysctl …

SpringBoot集成Camunda流程引擎 (一)

一、匹配版本简介 首先官网camunda7.17对应的springboot版本。camunda官网 camunda中文手册:Camunda 中文站 | docs.camunda.org 使用camunda流程引擎、web界面、Rest服务接口相应依赖如下: 流程引擎:camunda-bpm-spring-boot-starterRest服务接口:camunda-bpm…

深度学习中的两阶段目标检测

博主简介 博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的&#xff0c…

第五元素奏鸣曲:企业的新数据之道

1997年,吕克贝松指导的经典电影《第五元素》上映,引发了全球的科幻热潮。影片中,各界都在为追逐第五元素而努力。有趣的是,二十年过去,千行百业与亿万企业开始共同追逐一种新的“第五元素”——数据。数据之所以有这个…

走迷宫项目

这个项目主要就是基于easyx图形库来用的 先是把图片加载上去,但是我搞的时候忘记使用双缓冲绘图就会导致这个图片一直闪,而且物体移动会导致图片上面留下痕迹 于是就把双缓冲加上然后把图片也放入循环当中 就不会出现之前的情况; 我的物体移…

CTO:给我一个SpringBoot实现MySQL百万级数据量导出并避免OOM的解决方案

前言 动态数据导出是一般项目都会涉及到的功能。它的基本实现逻辑就是从mysql查询数据,加载到内存,然后从内存创建excel或者csv,以流的形式响应给前端。 参考:https://grokonez.com/spring-framework/spring-boot/excel-file-dow…

软件质量保证与软件测试 第三周(决策表+黑盒测试总结)+第四周(路径测试(白盒测试的一种)+各种覆盖判定的计算)

继续上周的等价类测试用例,例题3:佣金问题等价类测试用例 题目: 弱一般:max (2, 1, 1) 2 强一般:2*1*1 2 弱健壮:2 3*2 8 强健壮:4 * 3 * 3等价类的观察总结: 第三周 决…

DC3算法生成后缀数组详解

文章目录1、何为后缀数组2、暴力生成后缀数组3、用DC3算法生成后缀数组的流程4、DC3算法代码实现C版Java版5、DC3算法的地位1、何为后缀数组 假设有一个字符串 “aabaabaa”,从每个位置开始往后到最后一个位置得到的所有的「后缀字符串」” 下标7开头:…

电商项目8:平台属性

电商项目8&#xff1a;平台属性1、后端1.1、属性分组模糊查询1.2、商品属性新增功能&#xff1a;保存关联关系1、后端 1.1、属性分组模糊查询 需要改造。当前端传0时候。模糊查询功能有点问题 AttrGroupServiceImpl Overridepublic PageUtils queryPage(Map<String, Obje…

Java 进阶(10) 线程生命周期

线程的生命周期 五种基本状态 当线程被创建并启动以后&#xff0c;它既不是⼀启动就进⼊了执⾏状态&#xff0c;也不是⼀直处于执⾏状态。 新建状态&#xff08;New&#xff09; 当线程对象对创建后&#xff0c;即进⼊了新建状态&#xff0c;如&#xff1a; Thread t new M…

微服务架构中多级缓存设计

一.Nginx 缓存管理 在 Nginx 中自带将后端应用中图片、CSS、JS 等静态资源缓存功能&#xff0c; 我们只需在 Nginx 的核心配置 nginx.conf 中增加下面的片段&#xff0c; 便可对后端的静态资源进行缓存&#xff0c;关键配置我已做好注释&#xff0c; 可以直接使用; # 设置缓存…

同源策略与跨域

同源:协议、域名、端口号 必须完全相同。 违背同源策略就是跨域。 例如&#xff1a; 协议&#xff1a;http或者是https 域名&#xff1a;www.xxx.com 端口号&#xff1a;80&#xff0c;8000等。 同源&#xff1a;同一个来源。 同源&#xff1a;可以直接简写服务器页面的地址。…

激活数字营销新引擎,亚马逊云科技为企业带来数字化营销新体验

随着流量红利逐渐消失&#xff0c;营销触点呈现多元化&#xff0c;消费者决策变得复杂&#xff0c;利用数字化激活新的营销引擎成为破局关键。亚马逊云科技联合合作伙伴&#xff0c;基于智能湖仓打造了4个解决方案领域&#xff1a;一方数据平台、客户数字体验、广告智能分析、隐…

工具-win11系统,微软自带输入法输入“sj” 显示时间 【2022年01月11日 10:16:49】格式

文章目录1、前提2、操作3、碎碎念4、更新 2023年04月13日1、前提 下载某某输入法&#xff0c;输入“sj” 会自动显示【2023-04-11 09:57:01 】这样的格式&#xff0c;微软自带的输入法是显示【09点57分】的格式&#xff0c;但是由于个人工作学习需要&#xff0c;所以前者的键入…