tech share
  • tech-share
  • Engineering
    • 登录鉴权
    • SSR 页面路由
    • npm 版本号
    • 缓存
    • 数据库容灾
    • 动态效果导出 gif
    • Chrome-devtools
    • C 端 H5 性能优化
    • Docker
    • Monorepo 最佳实践
    • 技术架构演化
    • 项目规范最佳实践
    • snowpack
    • 静态资源重试
    • 前端页面渲染分析
    • Git
    • 前端重构
    • 微前端
    • 项目依赖分析
    • 前端监控原理
    • webpack
    • BS 架构与 CS 架构
    • HTTPS
    • package-lock.json 生成逻辑
    • SVN(Subversion)
    • 数据库分类
    • gulp
    • 前端架构
    • Bundle & Bundless
    • 控制反转 IoC
  • JavaScript
    • Javascript 性能
    • JavaScript 原型(2) - 原型与原型链
    • JavaScript 原型(1) - 构造函数
    • JavaScript - Promise
    • ES6 解构赋值
    • 前端离线化
    • Proxy
    • Object.defineProperty()简介
    • TypeScript
  • MachineLearning
    • GAN生成对抗网络
    • 虚拟对抗训练
    • 深度度量学习
    • 原型网络
    • PyTorch优化器
    • 隐马尔可夫模型2
    • Shapley Value 算法
    • Embarassingly Autoencoder算法
    • AutoRec算法及其后续发展
    • 深度学习常用激活函数
    • 序列预测ConvTran算法
    • 联邦学习
    • 深度学习推荐系统算法整理
    • 隐马尔可夫模型
    • 黎曼优化方法
    • FM算法
    • 机器学习常见评价指标
    • VAE算法
    • Adam优化器详解
    • Transformer算法
    • Self-attention 推荐算法
    • CNN 卷积神经网络
    • 图嵌入
    • 集成学习算法
    • RecBole开源框架
    • NCE-PLRec
    • 深度学习初始化方法
    • RNN循环神经网络
    • PyTorch数据处理
    • PyTorch安装和基本操作
    • XGBoost算法
    • NCF算法与简单MF的对比
    • 计算最佳传输
  • CSS
    • 什么是BFC
    • 纯CSS实现可拖动布局
    • 滚动穿透解决方案
  • React
    • React 生命周期
    • React Ref
    • React Hooks
    • SWR
    • React 数据流
    • React 函数式组件和类组件的区别
  • 可视化
    • OffscreenCanvas
    • Echarts 平滑曲线端点为什么不平滑
    • 颜色空间
    • 词云布局解析
    • 3D 数学基础
    • Canvas 图片处理
    • GLGL ES
    • WebGL 中绘制直线
    • Graphics API
    • 现代计算机图形学基础
    • Canvas 灰度
  • Vue
    • Vue2.x全局挂载整理
    • Vue2.6.x源码阅读
      • Vue2.6.x源码阅读 - 2.目录结构分析
      • Vue2.6.x源码阅读 - 4.源码阅读-platform
      • Vue2.6.x源码阅读 - 1.准备工作
      • Vue2.6.x源码阅读 - 5.源码阅读-core-Vue构造函数
      • Vue2.6.x源码阅读 - 7.源码阅读-core-响应式原理
      • Vue2.6.x源码阅读 - 3.源码阅读-shared
      • Vue2.6.x源码阅读 - 6.源码阅读-core-组件挂载
    • Vue + TypeScript Web应用实践
    • Vue2.x指令
    • nextTick()的使用
    • vue-cli2.x 的使用与项目结构分析
    • Vue响应式原理及总结
    • VueX的使用
    • Electron-Vue + Python 桌面应用实践
    • Vite
    • Vue组件通信整理
    • 记录一个问题的探索过程
  • Linux
    • memcg
  • GameDev
    • 游戏中的几种投影视图
    • 从零开始写软渲染器06
    • 从零开始写软渲染器05
    • 从零开始写软渲染器04
    • 从零开始写软渲染器03
    • 从零开始写软渲染器02
    • 从零开始写软渲染器01
    • 从零开始写软渲染器00
    • 现代游戏常用的几种寻路方案(一)
  • Node
    • NPM Dependency
    • Node 优势
    • Node Stream
    • Node 模块系统
  • HTML
    • html5语义与结构元素
  • 跨端
    • Flutter 介绍
  • Golang
    • Golang 基础
  • AR
    • SceneKit
由 GitBook 提供支持
在本页
  • Adam的发展
  • AdaGrad
  • RMSProp
  • AdaDelta
  • Adam算法具体思路和实现

这有帮助吗?

  1. MachineLearning

Adam优化器详解

最近在实验室搞的和某公司的校企合作面试中被问到有关Adam优化器的问题。笔者之前也总结过PyTorch中的几种常见优化器的接口和用法,但没有对原理进行详解。于是抽出时间对Adam优化器的细节进行了仔细的学习。

Adam的发展

Adam于2014年12月Kingma和Lei Ba两位学者提出,结合了AdaGrad和RMSProp的优点,对梯度的均值和方差进行综合考虑,计算更新的步长。

AdaGrad

我们都知道在一般的SGD算法中,参数每个维度都是依据相同的人为设定的梯度进行优化。

事实证明这种方法很多时候不能满足需要,这是由于不同维度上的梯度值并不一致。采取相同的学习率很多时候会造成某些梯度大的维度过早出现发散。

AdaGrad根据自变量在每个维度的梯度值的大小来调整各个维度上的学习率,从而避免统一的学习率难以适应所有维度的问题。

AdaGrad优化器维护一个变量s_t, 并用这个变量来控制学习率的变化。如果用x表示参数,g表示梯度,则s_t的更新公式如下:

s_t = s_(t-1) + g_t⊙g_t 

其中⊙表示逐个元素相乘,实际上就是得到了梯度的平方数值。很明显随着迭代次数的增加,s_t不断增加。

参数的更新公式如下:

x_t = x_(t-1) + [η / √(s_t + ε)] ⊙ g_t

其中η表示超参数基准学习率,ε通常设置为一个常数值,是为了保证数值的稳定,以及防止分母出现负值。该更新公式会随着迭代次数的增加不断降低学习率,同时由于s_t是一个长度为参数个输的向量,每个参数的学习率下降程度都是动态调整的。

通过pytorch进行一个简单的实现:

import torch
import torch.nn as nn

model = nn.Parameter(torch.randn(10, 1))

# 特征数量为10,10个样本。
x = torch.randn(10, 10)
y = torch.randn(10)
eta = 0.01
s = torch.zeros(10, 1)
for epoch in range(100):
    f = y - x.mm(model)
    f.backward()
    g = model.weight.grad
    model.weight = model.weight - (eta / torch.sqrt(s + 1)) * g
    s = s + g * g

adagrad主要缺点在于当梯度较大的时候,s_t会迅速变大,从而导致η迅速减小。这可能使得模型的训练停滞不前,寻找不到最佳的结果。

RMSProp

RMSProp和AdaGrad十分类似,区别在于为了避免学习率过早地降得太低,采用了一个超参数γ来控制梯度数值对于s_t的影响:

s_t = γ · s_(t-1) + (1 - γ) ` (g_t⊙g_t)

当γ值较大的时候,s_t的变化也会较小,从而模型可以以比较均匀的速度优化。当γ值较小的时候,s_t变化比较剧烈,从而学习率也会迅速减小,模型可以放慢优化速度以寻找最优解。

γ的引入使得使用者可以更加方便地控制学习率移动的幅度, 这种方法被称为指数加权移动平均(exponentially weighted moving average)。

AdaDelta

另一种进行指数加权移动平均的算法是AdaDelta算法。在RMSProp的基础上,该算法不再需要提供η这个基础学习率超参数。而是对参数的实际变化值进行指数加权移动平均。如下所示:

x_t = x_(t-1) + [√(Δx + ε) / √(s_t + ε)] ⊙ g_t

Δx初始化为0,然后通过下式进行迭代更新:

x_t = ρ · x_(t-1) + (1 - ρ) g' ⊙ g'

其中g'是经过学习率调整后的实际参数变化值。ρ和γ通常取相同的值。

Adam算法具体思路和实现

Adam(Adaptive moment estimation)算法是综合了RMSProp中的指数加权平均和SGD中的动量法思路。Adam采用两个不同的超参数β1和β2来控制动量以及RMSP中s_t的更新。

v_t = β1 · v_(t-1) + (1 - β1) · g_t
s_t = β2 · s_(t-1) + (1 - β2) · (g_t⊙g_t)

此外通过计算设计者发现在t时刻,各时刻动量的权值之和为1 - β1^t。为了保证在t较小时该值也能接近1,Adam算法会进行一次梯度修正。即:

v_t = v_t / (1 - β1^t)
s_t = s_t / (1 - β2^t)

每一轮实际梯度为

g_t' = η · v_t / (√s_t + ε)

Adam综合了动量法和指数加权平均的办法。从而也就综合了两者的优点。前者是参考了物理学中动量的概念,使得过去的梯度下降结果对本次梯度产生一定的影响,后者则是一定程度上避免了参数更新的发散。

上一页VAE算法下一页Transformer算法

最后更新于4年前

这有帮助吗?