26. 深度学习进阶 - 深度学习的优化方法

在这里插入图片描述

Hi, 你好。我是茶桁。

上一节课中我们预告了,本节课是一个难点,同时也是一个重点,大家要理解清楚。

我们在做机器学习的时候,会用不同的优化方法。

SGD

Alt text

上图中左边就是Batch Gradient Descent,中间是Mini-Batch Gradient Descent, 最右边则是Stochastic Gradient Descent。

我们还是直接上代码写一下来看。首先我们先定义两个随机值,一个x,一个ytrue:

import numpy as np
x = np.random.random(size=(100, 8))
ytrue = torch.from_numpy(np.random.uniform(0, 5, size=(100, 1)))

x是一个1008的随机值,ytrue是1001的随机值,在0到5之间,这100个x对应着这100个ytrue的输入。

然后我们来定义一个Sequential, 在里面按顺序放一个线性函数,一个Sigmoid激活函数,然后再来一个线性函数,别忘了咱们上节课所讲的,要注意x的维度大小。

linear = torch.nn.Linear(in_features=8, out_features=1)
sigmoid = torch.nn.Sigmoid()
linear2 = torch.nn.Linear(in_features=1, out_features=1)train_x = torch.from_numpy(x)model = torch.nn.Sequential(linear, sigmoid, linear2).double()

我们先来看一下训练x和ytrue值的大小:

print(model(train_x).shape)
print(ytrue.shape)---
torch.Size([100, 1])
torch.Size([100, 1])

然后我们就可以来求loss了,先拿到预测值,然后将预测值和真实值一起放进去求值。

loss_fn = torch.nn.MSELoss()
yhat = model(train_x)
loss = loss_fn(yhat, ytrue)
print(loss)---
36.4703

我们现在可以定义一个optimer, 来尝试进行优化,我们来将之前的所做的循环个100次,在其中我们加上反向传播:

optimer = torch.optim.SGD(model.parameters(), lr=1e-3)for e in range(100):yhat = model(train_x)loss = loss_fn(yhat, ytrue)loss.backward()print(loss)optimer.step()---
tensor(194.9302, dtype=torch.float64, grad_fn=<MseLossBackward0>)
...
tensor(1.9384, dtype=torch.float64, grad_fn=<MseLossBackward0>)

可以看到,loss会一直降低。从194一直降低到了2左右。

在求解loss的时候,我们用到了所有的train_x,那这种方式就叫做Batch gradient Descent,批量梯度下降。

它会对整个数据集计算损失函数相对于模型参数的梯度。梯度是一个矢量,包含了每个参数相对与损失函数的变化率。

这个方法会使用计算得到的梯度来更新模型的参数。更新规则通常是按照一下方式进行:

w t + 1 = w t − η ▽ w t \begin{align*} w_{t+1} = w_t - \eta \triangledown w_t \end{align*} wt+1=wtηwt

w t + 1 w_{t+1} wt+1是模型参数, η \eta η是学习率, ▽ w t \triangledown w_t wt是损失函数相对于参数的梯度。

但是在实际的情况下这个方法可能会有一个问题,比如说,我们在随机x的时候参数不是100,而是10^8,维度还是8维。假如它的维度很大,那么会出现的情况就是把x给加载到模型里面运算的时候,消耗的内存就会非常非常大,所需要的运算空间就非常大。

这也就是这个方法的一个缺点,计算成本非常高,由于需要计算整个训练数据集的梯度,因此在大规模数据集上的计算成本较高。而且可能会卡在局部最小值,难以逃离。说实话,我上面演示的数据也是尝试了几次之后拿到一次满意的,也遇到了在底部震荡的情况。

在这里可以有一个很简单的方法,我们规定每次就取20个:

for e in range(100):for b in range(100 // 20):batch_index = np.random.choice(range(len(train_x)), size=20)yhat = model(train_x[batch_index])loss = loss_fn(yhat, ytrue[batch_index])loss.backward()print(loss)optimer.step()

这样做loss也是可以下降的,那这种方法就叫做Mini Batch。

还有一种方法很极端,就是Stochhastic Gradient Descent,就是每次只取一个个数字:

for e in range(100):for b in range(100 // 1):...

这种方法很极端,但是可以每次都可以运行下去。那大家就知道,有这三种不同的优化方式。

Alt text

这样的话,我们来看一下,上图中的蓝色,绿色和紫色,分别对应哪种训练方式?

紫色的是Stochastic Gradient Descent,因为它每次只取一个点,所以它的loss变化会很大,随机性会很强。换句话说,这一次取得数据好,可能loss会下降,如果数据取得不好,它的这个抖动会很大。

绿色就是Mini-Batch, 我们刚才20个、20个的输入进去,是有的时候涨,有的时候下降。

最后蓝色的就是Batch Gradient Descent, 因为它x最多,所以下降的最稳定。

但是因为每次x特别多内存,那有可能就满了。内存如果满了,机器就没有时间去运行程序,就会变得特别的慢。

MOMENTUM

我们上面讲到的了这个式子:

w t + 1 = w t − η ▽ w t \begin{align*} w_{t+1} = w_t - \eta \triangledown w_t \end{align*} wt+1=wtηwt

这个是最原始的Grady descent, 我们会发现一个问题,就是本来在等高线上进行梯度下降的时候,它找到的不是最快的下降的那条线,在实际情况中,数据量会很多,数量会很大。比方说做图片什么的,动辄几兆几十兆,如果要再加载几百个这个进去,那就会很慢。这个梯度往往可能会变的抖动会很大。

那有人就想了一个办法去减少抖动。就是我们每一次在计算梯度下降方向的时候,连带着上一次的方向一起考虑,然后取一个比例改变了原本的方向。那这样的话,整个梯度下降的线就会平缓了,抖动也就没有那么大,这个就叫做Momentum, 动量。

v t = γ ⋅ v t − 1 + η ▽ w t w t + 1 = w t − v t \begin{align*} v_t & = \gamma \cdot v_{t-1} + \eta \triangledown w_t \\ w_{t+1} & = w_t - v_t \end{align*} vtwt+1=γvt1+ηwt=wtvt

动量在物理学中就是物体沿某个方向运动的能量。

之前我们每次的wt是直接去减去学习率乘以梯度,现在还考虑了v{t-1}的值,乘上一个gamma,这个值就是我们刚才说的取了一个比例。

Alt text

就像这个图一样,原来是红色,加了动量之后就变成蓝色,可以看到更平稳一些。

RMS-PROP

除了动量法之外呢,还有一个RMS-PROP方法,全称为Root mean square prop。

Alt text

S ∂ l o s s ∂ w = β S ∂ l o s s ∂ w + ( 1 − β ) ∣ ∣ ∂ l o s s ∂ w ∣ ∣ 2 S ∂ l o s s ∂ b = β S ∂ l o s s ∂ b + ( 1 − β ) ∣ ∣ ∂ l o s s ∂ b ∣ ∣ 2 w = w − α ∂ l o s s ∂ w S ∂ l o s s ∂ w b = b − α ∂ l o s s ∂ b S ∂ l o s s ∂ b \begin{align*} S_{\frac{\partial loss}{\partial w}} & = \beta S_{\frac{\partial loss}{\partial w}} + (1 - \beta)||\frac{\partial loss}{\partial w} ||^2 \\ S_{\frac{\partial loss}{\partial b}} & = \beta S_{\frac{\partial loss}{\partial b}} + (1 - \beta)||\frac{\partial loss}{\partial b} ||^2 \\ w & = w - \alpha \frac{\frac{\partial loss}{\partial w}}{\sqrt{S_{\frac{\partial loss}{\partial w}}}} \\ b & = b - \alpha \frac{\frac{\partial loss}{\partial b}}{\sqrt{S_{\frac{\partial loss}{\partial b}}}} \end{align*} SwlossSblosswb=βSwloss+(1β)∣∣wloss2=βSbloss+(1β)∣∣bloss2=wαSwloss wloss=bαSbloss bloss

这个方法看似复杂,其实也是非常简单。这些方法在PyTorch里其实都有包含,我们可以直接调用。我们在这里还是要理解一下它的原理,之后做事的时候也并不需要真的取从头写这些玩意。

在讲它之前,我们再回头来说一下刚刚求解的动量法,动量法其实已经做的比较好了,但是还是有一个问题,它每次的rate是人工定义的。也就是我们上述公式中的 γ \gamma γ, 这个比例是人工定义的,那在RMS-PROP中就写了一个动态的调整方法。

这个动态的调整方法就是我们每一次在进行调整w或者b的时候,都会除以一个根号下的 S ∂ l o s s ∂ w S_{\frac{\partial loss}{\partial w}} Swloss,我们往上看,如果 ∂ l o s s ∂ w \frac{\partial loss}{\partial w} wloss比较大的话,那么 S ∂ l o s s ∂ w S_{\frac{\partial loss}{\partial w}} Swloss也就将会比较大,那放在下面的式子中,根号下,也就是 S ∂ l o s s ∂ w \sqrt{S_{\frac{\partial loss}{\partial w}}} Swloss 在分母上,那么w就会更小,反之则会更大。

所以说,当这一次的梯度很大的时候,这样一个方法就让 ∂ l o s s ∂ w \frac{\partial loss}{\partial w} wloss其实变小了,对b来说也是一样的情况。

也就说,如果上一次的方向变化的很严重,那么这一次就会稍微的收敛一点,就会动态的有个缩放。那么如果上一次变化的很小,那为了加速它,这个值反而就会变大一些。

所以说他是实现了一个动态的学习率的变化,当然它前面还有一个初始值,这个 γ \gamma γ需要人为设置,但是在这个 γ \gamma γ基础上它实现了动态的学习速率的变化。

动态的学习速率考察两个值,一个是前一时刻的变化的快慢,另一个就是它此时此刻变化的快慢。这个就叫做RMS。

ADAM

那我们在这里,其实还有一个方法:ADAM。
V d w = β 1 V d w + ( 1 − β 1 ) d w V d b = β 1 V d b + ( 1 − β 1 ) d b S d w = β 2 S d w + ( 1 − β 2 ) ∣ ∣ d w ∣ ∣ 2 S d b = β 2 S d b + ( 1 − β 2 ) ∣ ∣ d b ∣ ∣ 2 V d w c o r r e c t e d = V d w 1 − β 1 t V d b c o r r e c t e d = V d b 1 − β 1 t S d w c o r r e c t e d = S d w 1 − β 2 t S d b c o r r e c t e d = S d b 1 − β 2 t w = w − α V d b c o r r e c t e d S d w c o r r e c t e d + ε b = b − α V d b c o r r e c t e d S d b c o r r e c t e d + ε \begin{align*} V_{dw} & = \beta_1V_{dw} + (1-\beta_1)dw \\ V_{db} & = \beta_1V_{db} + (1-\beta_1)db \\ S_{dw} & = \beta_2S_{dw} + (1-\beta_2)||dw||^2 \\ S_{db} & = \beta_2S_{db} + (1-\beta_2)||db||^2 \\ & V_{dw}^{corrected} = \frac{V_{dw}}{1-\beta_1^t} \\ & V_{db}^{corrected} = \frac{V_{db}}{1-\beta_1^t} \\ & S_{dw}^{corrected} = \frac{S_{dw}}{1-\beta_2^t} \\ & S_{db}^{corrected} = \frac{S_{db}}{1-\beta_2^t} \\ w & = w - \alpha\frac{V_{db}^{corrected}}{\sqrt{S_{dw}^{corrected}}+\varepsilon} \\ b & = b - \alpha\frac{V_{db}^{corrected}}{\sqrt{S_{db}^{corrected}}+\varepsilon} \\ \end{align*} VdwVdbSdwSdbwb=β1Vdw+(1β1)dw=β1Vdb+(1β1)db=β2Sdw+(1β2)∣∣dw2=β2Sdb+(1β2)∣∣db2Vdwcorrected=1β1tVdwVdbcorrected=1β1tVdbSdwcorrected=1β2tSdwSdbcorrected=1β2tSdb=wαSdwcorrected +εVdbcorrected=bαSdbcorrected +εVdbcorrected

刚刚讲过的RMS特点其实是动态的调整了我们的学习率,之前讲Momentum其实还保持了上一时刻的方向,RMS就没有解决这个问题,RMS把上一时刻的方向给弄没了。

RMS,它的定义其实就没有考虑上次的方向,它只考虑上次变化的大小。而现在提出来这个ADAM,这个ADAM的意思就是Adaptive Momentum, 还记不记得咱们讲随机森林和Adaboost那一节,我们讲过Adaboost就是Adaptive Boosting,这里的Adaptive其实就是一个意思,就是自适应动量,也叫动态变化动量。

ADAM就结合了RMS和动量的两个优点。第一个是他在分母上也加了一个根号下的数,也就做了RMS做的事,然后在分子上还有一个数,这个数就保留了上一时刻的数,比如 V d w c o r r e c t e d V_{dw}^{corrected} Vdwcorrected, 就保留了上一时刻的V,就保留了上一时刻的方向。

所以ADAM既是动态的调整了学习率,又保留了上一时刻的方向。

那除此之外,其实还有一个AdaGrad和L-BFGS方法,不过常用的方法也就是上面详细讲的这几种。

到此为止,我们进阶神经网络的基础知识就都差不多具备了,接下来我们就该来讲解下卷机和序列,比如说LSTM和RNN、CNN的东西。在这些结束之后,我们还会有Attention机制,Transformer机制,YOLO机制,Segmentation机制,还有强化深度学习其实都是基于这些东西。

那我们下节课,就先从RNN来说开去。

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

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

相关文章

【Linux】第二十五站:深入理解文件系统

文章目录 一、前言二、认识硬件----磁盘1.基本介绍2.磁盘的存储构成3.磁盘的逻辑结构4.回归到硬件 三、文件系统1.划分2.Block group(1)Data blocks(2)inode Table(3)Block Bitmap(4)inode Bitmap(5)Group Descriptor Table(GDT)(6)Super Block 3.总结4.一些其他问题5.如何理解…

untiy webgl常见问题与操作

文章目录 1 untiy和网页相互通信2 打开新页面&#xff08;同标签页和新标签页&#xff09;3 获取网页的URL4 解析Url内的参数5 后处理与色彩空间问题 1 untiy和网页相互通信 看这个文章 2 打开新页面&#xff08;同标签页和新标签页&#xff09; 先看本文untiy和网页相互通信…

翻译: GPT4等大型语言模型的原理解析和未来预测慢思考和模型自我迭代和LLM安全

YouTube: Intro to Large Language Models - YouTube 1. Large Language Model LLM 大家好&#xff0c;最近我做了一个关于大型语言模型的 30 分钟演讲&#xff0c;有点像介绍性演讲&#xff0c;不幸的是&#xff0c;那个演讲没有被录制下来&#xff0c;但很多人在演讲结束后…

基于JNI实现调用C++ SDK

基于JNI实现调用C SDK 背景分析解决实践 背景 上篇文章总结了几种Java项目调用C/C SDK项目方法&#xff0c;在逐一实践、踩坑后&#xff0c;最终还是敲定采用 JNI 方式进行实现。在文章开始的过程&#xff0c;会先大概讲讲笔者遇到的情况&#xff0c;因为封装方式需要根据实际…

MQTT客户端、代理(broker)和连接建立

在前篇文章&#xff08;http://t.csdnimg.cn/IamPz&#xff09;中&#xff0c;介绍了发布/订阅架构和MQTT如何据此交换信息&#xff0c;其中的关键概念是&#xff1a; 发布/订阅架构触耦了负责发布信息的客户端&#xff08;发布者&#xff09;和负责接收信息的客户端&#xff…

[c]求逆序数

#include<stdio.h> int main() {int n,i,count;scanf("%d",&n);int arr[n];count0;for(i0;i<n-1;i){scanf("%d",&arr[i]);}for(int j0;j<n-2;j)//注意是小于等于n-2&#xff0c;因为倒数第一个元素后面没有数了&#xff0c;不需要比较…

CSC173 Boolean Logic and Boolean Circuits

We have provided code for a simple Boolean circuit simulator written i n C

韵达速递查询,韵达速递单号查询,对需要的单号进行备注

批量查询韵达速递单号的物流信息&#xff0c;对需要的单号进行备注。 所需工具&#xff1a; 一个【快递批量查询高手】软件 韵达速递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左上角的“…

基于SpringBoot + vue的在线视频教育平台

qq&#xff08;2829419543&#xff09;获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;springboot 前端&#xff1a;采用vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xf…

王炸cpu-龙芯3A6000

国产 CPU 性能媲美 Intel 酷睿这事儿&#xff0c;可能真的已经实现了。 没错&#xff0c;那颗有着多次爆料拉满大家期待值的龙芯 3A6000&#xff0c;终于正式发布。 就在今天上午&#xff0c;龙芯中科在 2023 年龙芯产品发布暨用户大会上正式带来了这颗 CPU。 整场发布会 PPT …

【选择题】校招笔试选择题第一辑

题目 以下程序的运行结果是&#xff08; &#xff09; #include <stdio.h> int main(void) {printf("%s , %5.3s\n", "computer", "computer");return 0; }A. computer , puter B. computer , com C. computer , computer D. computer…

半导体封装之倒装封装 (Flip Chip)

倒装封装 &#xff08;Flipchip&#xff09;是相对于引线键合(Wire Bonding)来说的&#xff0c;之所以叫做倒装&#xff0c;是因为flip chip是正面朝下放置。倒装芯片技术是通过芯片上的凸点直接将元器件朝下互连到基板、载体或者电路板上。引线键合的连接方式是将芯片的正面朝…

笔记本电脑关闭触摸板

大部分人用笔记本 其实都是外接的鼠标 那么在打游戏 以及一些切图操作中 为了防止碰到触摸板导致误操作 我们就可以将他关掉 我们可以按快捷键 Win i 或者 点击桌面 此电脑/我的电脑/此计算机 打开设置界面 如果 左侧菜单中有设备 那么 直接点击设备 然后左侧菜单就会有 触摸…

详细了解 MOSFET 晶体管

MOSFET 开关晶体管 MOS 管是 “金属&#xff08;Metal&#xff09;氧化物&#xff08;Oxide&#xff09;半导体&#xff08;Semi&#xff09;” 场效应晶体管&#xff0c;或者称是 “金属&#xff08;Metal&#xff09;绝缘体&#xff08;Insulator&#xff09;半导体&#xf…

2022CVPR(PoseC3D):Revisiting Skeleton-based Action Recognition

Revisiting Skeleton-based Action Recognition 摘要1、引言2、相关工作3、框架3.1. 姿势提取的良好实践3.2.从2D姿势到3D热图体积3.3.基于骨架的动作识别的3D-CNN 4、实验4.2.姿势提取4.3. 3D热图体积的预处理4.4.与GCN的比较4.5. RGBPose-SlowFast4.6.与最先进的比较 5、结论…

【蓝桥杯】带分数

带分数 题目要求用一个ab/c的形式得到一个值&#xff0c;而且只能在1~9里面不重复的组合。 可以对1~9进行全排列&#xff0c;然后不断划分区间。 #include<iostream> #include<vector> using namespace std; int st[15]; int num[15]; int res; int n;int calc(i…

如何成为一名高效的前端开发者(10X开发者)

如今&#xff0c;每个人都想成为我们所说的“10倍开发者”。然而&#xff0c;这个术语经常被误解和高估。 本质上&#xff0c;一个高效或者10倍开发者&#xff0c;在我看来&#xff0c;是指那些能够充分利用所有可用工具的人&#xff0c;通过让这些工具处理冗余和重复的任务&am…

C语言-联合和枚举

------------------------------------ --------------- ------ 最慢的步伐不是跬步&#xff0c;而是徘徊&#xff1b; 最快的脚步不是冲刺&#xff0c;而是坚持。 今天来到我们的联合和枚举类型的讲解&#xff1a; 目录 联合体类型 联合体类型的声明 联合体类型的特点 …

LeetCode(50)有效的括号【栈】【简单】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 有效的括号 1.题目 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串是否有效。 有效字符串需满足&#xff1a; 左括号必须用相同类型的右括号闭合…

深度学习记录--初识向量化

什么是向量化&#xff1f; 之前计算logistic回归损失函数时&#xff0c;在代码实现时&#xff0c;讨论了for循环&#xff1a;过多的for循环会拖慢计算的速度(尤其当数据量很大时) 因此&#xff0c;为了加快计算&#xff0c;向量化是一种手段 运用python的numpy库&#xff0c…