【深度学习】5-1 与学习相关的技巧 - 参数的更新(Momentum,AdaGrad, Adam )

神经网络的学习的目的是找到使损失函数的值尽可能小的参数。这是寻找最优参数的问题,解决这个问题的过程称为最优化

但是神经网络的最优化问题非常难。这是因为参数空间非常复杂,无法轻易找到最优解。而且,在深度神经网络中,参数的数量非常庞大,导致最优化问题更加复杂。

SGD

在前面,为了找到最优参数,我们将参数的梯度(导数)作为了线索,使用参数的梯度,沿梯度方向更新参数,并重复这个步骤多次,从而逐渐靠近最优参数,这个过程称为随机梯度下降法,称SGD

用数学式可以将 SGD 写成如下的式子:
在这里插入图片描述
这里把需要更新的权重参数记为 在这里插入图片描述,把损失函数关于 的梯度记为η 。式子中的←表示用右边的值更新左边的值。

SGD是朝着梯度方向只前进一定距离的简单方法。现在,我们将SGD实现为一个Python类(为方便后面使用,我们将其实现为一个名为SGD的类)。

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]

此外,代码段中还定义了update(params,grads)方法这个方法在SGD中会被反复调用。

使用这个SGD类,可以按如下方式进行神经网络的参数的更新(下面的代码是不能实际运行的伪代码)。

network = TwoLayerNet(...)
optimizer = SGD()

for i in range(10000):
	...
	x_batch, t_batch = get_mini_batch(...) # mini-batch
	grads = network.gradient(x_batch, t_batch)
	params = network.params
	optimizer.update(params, grads)
	...

这里optimzer表示“优化器”,这里由SGD承担这个角色。参数的更新由optimizer负责完成。

SGD的缺点
虽然SGD简单,并且容易实现,但是在解决某些问题时可能没有效率。SGD的缺点是,如果函数的形状非均向,比如呈延伸状,搜索的路径就会非常低效。因此,我们需要比单纯朝梯度方向前进的SGD更聪哪的方法。SGD低效的根本原因是,梯度的方向并没有指向最小值的方向

为了改正SGD的缺点,下面使用MomentumAdaGradAdam这林方法来取代SGD。

基于 SGD 的最优化的更新路径:呈“之”字形朝最小值 (0, 0) 移动,效率低
在这里插入图片描述

Momentum

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

这里新出现了一个变量v,对应物理上的速度,表示了物体在梯度方向上受力,在这个力的作用下,物体的速度加这一物理法则。
式子中有av这一项。在物体不受任何力时,该项承担使物体逐渐减速的任务,对应物理上的地面摩擦或空气阻力
Momentum的实现代码如下:
在这里插入图片描述
Momentum 方法给人的感觉就像是小球在地面上滚动。
在这里插入图片描述
式子中的av对应物理上的地面摩擦或空气阻力,下面是代码实现

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]

实例变量v会保存物体的速度。初始化时,v中什么都不保存,但当第一次调用update()时,v会以字典型变量的形式保存与参数结构相同的数据。

在下图中,更新路径就像小球在碗中滚动一样。和SGD相比,我们发现“之”字形的“程度”减轻了。这是因为虽然x轴方向上受到的力非常小,但是一直在同一方向上受力,所以朝同一个方向会有一定的加速。反过来,虽微y轴方向上受到的力很大,但是因为交互地受到正方向和反方向的力,它们会互相抵消,所以y轴方向上的速度不稳定。因此,和SGD时的情形相比可以更快地朝x轴方向靠近,减弱“之”字形的变动程度
在这里插入图片描述

AdaGrad

在关于学习率的有效技巧中,有一种被称为学习率衰减的方法,即随着学习的进行,使学习率逐渐减小。实际上,一开始“多”学,然后逐渐“少”学的方法,在神经网络的学习中经常被使用。

AdaGrad针对“一个一个”的参数,赋予其“定制”的值。AdaGrad会为参数的每个元素适当地调整学习率,与此同时进行学习。
下面用数学式表示AdaGrad的更新方法
在这里插入图片描述
在这里插入图片描述

这里新出现了变量h,如式子所示,它保存了以前的所有梯度值的平方和(式子中的符号表示对应矩阵元素的乘法)
然后,在更新参数时,通过乘以在这里插入图片描述
,就可以调整学习的尺度。这意味着参数的元素中变动较大(被大幅更新)的元素的学习率将变小。也就是说可以按参数的元素进行学习率衰减,使变动大的参数的学习率逐渐减小。

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

AdaGrad的实现过程如下所示:

class 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)

这里需要注意的是,最后一行加上了微小值1e-7
在这里插入图片描述

函数的取值高效地向着最小值移动。由于y轴方向上的梯度较大,因此刚开始变动较大,但是后面会根据这个较大的变动按比例进行调整,减小更新的步伐。

Adam

将Momentum和AdaGrad这两个方法融合在一起就是Adam方法的基本思路。此外,进行超参数的“偏置校正”也是 Adam 的特征。
下面是Python实现的Adam类,

class 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)

在这里插入图片描述
基于Adam的更新过程就像小球在碗中滚动一样。虽然Momentun也有类似的移动,但是相比之下,Adam的小球左右摇晃的程度有所减轻。这得益于学习的更新程度被适当地调整了。.

使用哪种更新方法
到目前为止,我们已经学习了 4 种更新参数的方法。
这 4 种方法各有各的特点,都有各自擅长解决的问题和不擅长解决的问题。
很多研究中至今仍在使用 SGD。Momentum 和 AdaGrad 也是值得一试的方法。最近,很多研究人员和技术人员都喜欢用 Adam。这里还是主要使用 SGD 或者 Adam

基于MNIST数据集的更新方法的比较
以手写数字识别为例,比较前面介绍的SGD、Momentum、AdaGrad、Adam这4种方法,并确认不同的方法在学习进展上有多大程度的差异。
这个实验以一个5层神经网络为对象,其中每层有100个神经元。激活函数使用的是ReLU

看代码:

# coding: utf-8
import os
import sys
sys.path.append(os.pardir)  # 为了导入父目录的文件而进行的设定
import matplotlib.pyplot as plt
from dataset.mnist import load_mnist
from common.util import smooth_curve
from common.multi_layer_net import MultiLayerNet
from common.optimizer import *


# 0:读入MNIST数据==========
(x_train, t_train), (x_test, t_test) = load_mnist(normalize=True)

train_size = x_train.shape[0]
batch_size = 128
max_iterations = 2000


# 1:进行实验的设置==========
optimizers = {}
optimizers['SGD'] = SGD()
optimizers['Momentum'] = Momentum()
optimizers['AdaGrad'] = AdaGrad()
optimizers['Adam'] = Adam()
#optimizers['RMSprop'] = RMSprop()

networks = {}
train_loss = {}
for key in optimizers.keys():
    networks[key] = MultiLayerNet(
        input_size=784, hidden_size_list=[100, 100, 100, 100],
        output_size=10)
    train_loss[key] = []    


# 2:开始训练==========
for i in range(max_iterations):
    batch_mask = np.random.choice(train_size, batch_size)
    x_batch = x_train[batch_mask]
    t_batch = t_train[batch_mask]
    
    for key in optimizers.keys():
        grads = networks[key].gradient(x_batch, t_batch)
        optimizers[key].update(networks[key].params, grads)
    
        loss = networks[key].loss(x_batch, t_batch)
        train_loss[key].append(loss)
    
    if i % 100 == 0:
        print( "===========" + "iteration:" + str(i) + "===========")
        for key in optimizers.keys():
            loss = networks[key].loss(x_batch, t_batch)
            print(key + ":" + str(loss))


# 3.绘制图形==========
markers = {"SGD": "o", "Momentum": "x", "AdaGrad": "s", "Adam": "D"}
x = np.arange(max_iterations)
for key in optimizers.keys():
    plt.plot(x, smooth_curve(train_loss[key]), marker=markers[key], markevery=100, label=key)
plt.xlabel("iterations")
plt.ylabel("loss")
plt.ylim(0, 1)
plt.legend()
plt.show()

结果图如下
在这里插入图片描述
从图的结果中可知,与SGD相比,其他3种方法学习得更快,而目速度基本相同。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

selenium.chrome怎么写扩展拦截或转发请求?

Selenium WebDriver 是一组开源 API,用于自动测试 Web 应用程序,利用它可以通过代码来控制chrome浏览器! 有时候我们需要mock接口的返回,或者拦截和转发请求,今天就来实现这个功能。 代码已开源: https:/…

9k字长文理解Transformer: Attention Is All You Need

作者:猛码Memmat 目录 Abstract1 Introduction2 Background3 Model Architecture3.1 Encoder and Decoder Stacks3.2 Attention3.2.1 Scaled Dot-Product Attention3.2.2 Multi-Head Attention3.2.3 Applications of Attention in our Model 3.3 Position-wise Feed…

C++基础(6)——类和对象(运算符重载)

前言 本文主要介绍了C中运算符重载的基本知识。 4.5.1:加号运算符重载(成员函数和全局函数都可实现) 运算符重载:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 1:成员…

防火墙日志记录和监控在网络安全中的重要性

防火墙监视进出网络的流量,并保护部署网络的网络免受恶意流量的侵害。它是一个网络安全系统,根据一些预定义的规则监控传入和传出的流量。它以日志的形式记录有关如何管理流量的信息。日志数据包含流量的源和目标 IP 地址、端口号、协议等。为了有效地保…

Git系列:运用Git创建空白分支进行项目相关文档管理

文章目录 起因一、为什么会选择Git分支二、Git分支的简单介绍和好处三、本次的具体操作1.$git checkout --orphan XXX2.删除当前分支里的内容3.提交新的分支 总结 起因 项目管理过程中没有做好相关文档管理,比如需求,开发,测试等文档&#x…

科技云报道:大模型时代,AI基础软件机会何在?

科技云报道原创。 大模型时代,离不开算力,算法、数据的喂养。如果将视角放至整个产业链上,算法背后,还有一个关键要素值得被关注,那就是AI基础软件。 算法是实现AI功能的关键,而基础软件则为算法提供运行…

React项目引入Arco Design,以及Arco Design Pro 架构

创建项目 创建 react-arco 项目 pnpm create vite my-vue-app --template react安装 arco-design/web-react 安装 react 版的 arco-design 基础使用 添加一个按钮,App.tsx import "./App.css"; import { Button } from "arco-design/web-react…

CH2023、Adobe Character Animator 2023(动画角色制作软件)下载教程、安装教程

最后附下载地址 Adobe CH简介: Adobe Character Animator是一款基于动画制作的软件,它可以将手绘的角色通过摄像头或麦克风捕捉到的实时动作转化为动画效果。该软件结合了人工智能和动画技术,可以快速创建高质量的角色动画,并且…

2023年的深度学习入门指南(17) - 深度学习的硬件加速技术

2023年的深度学习入门指南(17) - 深度学习的硬件加速技术 有了前面的知识之后,想必大家对于算力需求的理解已经越来越深刻了。 除了使用CPU,GPU这样的通用器件之外,采用专用的硬件来进行加速是一个大家都能想到的选择。 其中的代表器件就是…

杂记 | 使用Docker和Nginx为网站添加HTTPS访问功能

文章目录 01 准备工作1.1 HTTPS介绍1.2 准备工作 02 编写nginx.conf03 使用docker启动nginx 01 准备工作 1.1 HTTPS介绍 HTTPS(Hypertext Transfer Protocol Secure)是一种通过加密通信保护网站数据传输的协议。它是 HTTP 协议的安全版本,通…

1.4 掌握Scala运算符

一、运算符等价于方法 (一)运算符即方法 op运算符与.op方法调用是等价的,op表示运算符:、-、*、/…… 演示x y与x.(y)的等价 (二)方法即运算符 1、单参方法 str.indexOf(‘a’) 与 str indexOf ‘a’…

stable-diffusion-webui的介绍与使用——Controlnet1.1

源码地址:https://github.com/lllyasviel/ControlNet | 最新版本 controlnet-v1.1 论文地址:2302.Adding Conditional Control to Text-to-Image Diffusion Models 扩展UI地址(需先安装sd-webui):https://github.com/M…

【gcc, cmake, eigen, opencv,ubuntu】四.opencv安装和使用,获取opencv matiax 的指针

文章目录 ubuntu系统安装opencv1.下载opencv和opencv_contrib2.安装指导3.Linux 下 fatal error: opencv2/opencv.hpp: 没有那个文件或目录4.g 和cmake 编译使用opencv的程序5.opencv,eigen速度比较6.opencv常用类型符号7.获取opencv matiax 的指针 ubuntu系统安装opencv 1.下…

设计模式大全

使用设计模式的目的: 程序猿在编码的过程中面临着来自耦合性、内聚性、可维护性、可扩展性、重用性、灵活性等多方面的挑战。设计模式是为了让程序具有更好的: 1)重用性,即相同功能的代码编写一次即可,不用重复编写 …

史上最全Hadoop面试题:尼恩大数据面试宝典专题1

说在前面: 《尼恩 大数据 面试宝典》 是 《尼恩Java面试宝典》 姊妹篇。 这里特别说明一下:《尼恩Java面试宝典》41个专题 PDF (请在文末获取)自发布以来, 已经收集了 好几千题, 足足4000多页&#xff0c…

haproxy

haproxy haproxy一:常见的Web集群调度器1.软件2.硬件3.LVS ,Nginx ,Haproxy 的区别: 二:Haproxy应用分析1.HAProxy的主要特性有:2.HAProxy负载均衡策略非常多,常见的有如下8种: 三&a…

【深度学习】YOLOv8训练过程,YOLOv8实战教程,目标检测任务SOTA,关键点回归

文章目录 可用资源资源安装模型训练(检测)模型pridict模型导出 可用资源 https://github.com/ultralytics/ultralytics 官方教程:https://docs.ultralytics.com/modes/train/ 资源安装 更建议下载代码后使用 下面指令安装,这样…

C高级 day37

1、编写一个名为myfirstshell.sh的脚本,它包括以下内容。 1、包含一段注释,列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOME的值…

uniapp实现应用wgt资源热更新

APP更新一般有两种形式 1、整包更新,通过hbuliderx提供的在线云打包就属于整包更新,属于全量更新,缺点就是打包时间长、要重新走市场审核。费时 2、wgt资源包热更新,通过hbuliderx打wgt包 ,速度快,能在应用…

28.vite

目录 1 一些概念 1.1 单页面应用程序SPA 1.2 vite 2 初始化vite项目 3 项目中的文件 1 一些概念 1.1 单页面应用程序SPA 单页面应用程序是只有一个页面的前端,切换页面通过前端路由来切换 特点如下 实现了前后端分离,后端仅出接口&#…