CS231n-2017 Lecture7训练神经网络(二)笔记

本节主要是神经网络的动态部分,也就是神经网络学习参数和搜索最优超参数的过程

梯度检查:

进行梯度检查,就是简单地把解析梯度与数值计算梯度进行比较,防止反向传播的逻辑出错,仅在调试过程中使用。有如下技巧 :

使用中心化公式:

在使用有限差值近似计算数值梯度时,常见的公式是:

\frac{df(x)}{dx} = \frac{f(x+h)-f(x)}{h} h是一个很小,近似为1e-5的数,但这个公式不常用且不好用

经常使用的是下方的中心化公式:

\frac{df(x)}{dx} = \frac{f(x+h)-f(x-h)}{2h}

该公式在检查每个梯度的维度的时候,要求计算两次损失函数,但梯度的近似值会准确很多,因为使用泰勒展开(这里假设原函数可以泰勒展开),则中心化公式的误差近似O(h^2)

使用相对误差来比较:

比较数值梯度f^{'}_n与解析梯度f_a^{'}有哪些需要注意的细节,进而知道他们不匹配呢?

通常使用相对误差来进行量化,即:

\frac{|f_a^{'}-f_n^{'}|}{max(|f_a^{'}|,|f_n^{'}|)}

当然,还必须注意两个式子的梯度都为0的情况

量化阈值如下:

相对误差>1e-2:通常意味着梯度出错

1e-2>相对误差>1e-4:较有可能出错

1e-4>相对误差:对有不可导点的目标函数可以接受,但若目标函数中没有(tanh和softmax),这个相对误差还是太高

1e-7>相对误差:认为正常

以上的浮点数运算都要使用双精度浮点数

目标函数的不可导点(kinks):

在进行梯度检查时,不可导点是导致不准确的原因之一,可能是由ReLU,SVM损失、Maxout神经元等引入,也就是x+h在不可导点的一侧,而x-h在不可导点的另一侧导致的。在计算损失的过程中,是可以知道不可导点有没有被跨过的,在具有max形式的函数中持续追踪保留梯度的变量身份,就可以实现这一点,若在计算f(x+h)和f(x-h)的时候,至少有一个变量其梯度保留情况变了,就说明不可导点被越过了,数值梯度会不准确

使用少量数据点:

解决上述不可导点问题的一个方法,因为含有不可导点的损失函数的数据点越少,在计算梯度时越过不可导点的概率就越小,所以使用少量数据点,可以使梯度检查变高效

设置合适的步长h:

数值计算梯度的h并不是越小越好,当h特别小时,很可能会遇到数值精度问题,当梯度检查出问题时,不妨将h调大一点,可能会恢复正常

梯度检查的时间:

梯度检查时在参数空间中的一个特定单独点(往往随机取)进行的,即使是在该点梯度检查成功了,也不能马上确保全局上的梯度实现都是正确的,且随机的初始化可能不是参数空间中最优的代表性的点,这可能会导致梯度表面上正确实现。比如,SVM使用小数值权重初始化,就会把一些接近于0的得分分配给所有的数据点,而梯度将会在所有的数据点中展现出某种模式,不正确实现的梯度也许仍然能够产生出这种模式,但是其无法泛化到更具代表性的操作模式,比如在一些数据点的得分比另一些要大的时候失效。因此,最好让网络学习先“预热”一小段时间,等到损失函数开始下降之后,再进行梯度检查。在第一次迭代就进行梯度检查的话,若此时处于不正确的梯度边界情况,无法被察觉,从而掩盖了梯度没有正常实现的事实

正则化盖过数据损失:

Loss通常是数据损失和正则化损失的和,在某种情况,正则化损失的梯度有可能会远大于数据损失,进而掩盖掉数据损失梯度的不正确实现。因此,推荐先关掉正则化,单独对数据损失做梯度检查,然后再对正则化损失做梯度检查

关闭Dropout和数据扩张(augmentation):

在进行梯度检查时,需要关闭具有不确定效果的操作,比如Dropout和随机数据扩展,否则会在计算数值梯度时导致巨大误差。但是,关闭这些操作,会导致无法对这些操作进行梯度检查,所以,更好的方法是在计算f(x+h)和f(x-h)之前,强制增加一个特定的随机种子,确保伪随机

检查少量的维度:

实际模型中,梯度可以有上百万的参数,这种情况下只能够检查其中的一些维度,然后假设其他维度是正确的,但是要确认在所有不同的参数中都抽取一部分来梯度检查,比如可能偏置会占掉权重矩阵的一部分,则随机有概率只随机到偏置参数

进行参数学习之前的合理性检查:

1.寻找特定情况的正确损失值

在使用小参数进行初始化时,确保得到的损失值与期望一致。最好先单独检查数据损失(令正则化损失为0),若跑出来损失值与期望不一致,那么可能在初始化中就出了问题

2.提高正则化强度时,观察损失值是否变大

3.对小数据子集过拟合:

在整个数据集进行训练之前,尝试在一个很小的数据集上进行训练,然后确保能到达0的损失值,最好令正则化强度为0。除非能通过这一个过拟合检查,否则对整个数据集进行训练时没有意义的。但是,能对小数据子集进行过拟合,不代表完全正确,仍有可能存在不正确的实现,比如,因为某些错误原因,数据点的特征是随机的,这样算法也有可能对小数据进行过拟合,但在整个数据集上训练的时候,就不会产生泛化能力。

检查整个学习过程:

在训练神经网络时,需要追踪多个重要数值

在下方的图表中,x轴通常表示周期(epochs)单位,该单位衡量了在训练中每个样本数据都被观测过的次数的期望

损失函数:

训练期间第一个要跟踪的数字就是Loss,它在前向传播时对每个独立的batch数据进行计算

左图不同曲线对应了不同学习率下loss随epoch的变化,可以看到,过低的学习率导致loss的下降是现行的,高一些的学习率会看起来呈几何指数下降。更高的学习率会使Loss下降得很快,但是接下来就会停在一个不好的损失值上(绿线)。这是因为最优化的能量太大,参数只能在混沌中随机震荡,无法最优化到一个很好的点上。

右图显示了一个经典的随时间变化的损失函数值

损失值的震荡程度和batch size有关,当batch size = 1时,震荡会相对较大,当batch size 就是整个数据集时,震荡就会最小,因为这时每次梯度更新都是在单调地优化Loss

训练集和验证集准确率:

在训练分类器的时候,需要跟踪的第二重要的数字就是验证集和训练集的准确率,这个图表能够使我们了解模型过拟合的程度

训练集准确率和验证集准确率之间的间隔指明了模型过拟合的程度,比如

蓝色的验证集正确率相较于训练集正确率低了很多,就说明模型有很强的过拟合,遇到这种情况,就应该增大正则化强度,或者收集更多的训练数据

另一种情况是验证集曲线和训练集曲线相近,这种情况说明模型参数容量不够大,需要增大参数数量

权重更新比例:

最后一个需要跟踪的量是权重中所有更新值的和与全部权重值之和的比例,一个经验的结论是,这个比例应该要在1e-3左右,如果更低,说明学习率太小,如果更高,说明学习率过高

每层的激活数据及梯度分布:

一个不正确的初始化可能使学习过程变慢,甚至停止。其中一个检查方法就是输出网络所有层的激活数据和梯度的柱状图,直观的来说,如果看到任何奇怪的分布情况,那很可能有异常。如,对使用tanh的神经元,我们应该看到激活数据的值在整个[-1,1]区间中都有分布,如果看到神经元的输出全都是0,或者全都聚集在-1/1,那就肯定有问题了

第一层可视化:

如果数据是图像像素数据,那么把第一层特征可视化会有帮助,如图:

这是将神经网络第一层权重可视化的例子,可以发现左侧的特征中充满了噪声,这暗示网络可能出现了问题:网络没有收敛、学习率设置不恰当,正则化惩罚的权重过低等

而右图的特征就不错,平滑干净且种类繁多,说明训练过程良好进行

参数更新:

在能使用反向传播计算梯度的前提下,梯度就能够被用来进行参数更新了

随机梯度下降及各种更新方法:

普通更新:

最简单的更新形式就是沿着负梯度方向改变参数(因为梯度指向的是上升方向,但我们通常希望最小化损失函数),假设有参数向量x和梯度dx,则简单的更新形式为:

x+= - learning_rate * dx

动量(Momentum)更新:

这个方法在深度网络中几乎总能得到更好的收敛速度

原理:

我们将Loss理解为山的高度(而重力势能是U=mgh,所以有U正比于h),用随机数字初始化参数等同于在某个位置给质点设置初速度为0,则最优化过程可以看作是模拟参数向量(质点)在地形上滚动的过程

因为作用于质点的力与梯度的潜在能量有关(Fh = W = -U = -mgh \Rightarrow F=-\nabla U),质点所受的力就是损失函数的负梯度,又因为F=ma,所以负梯度与质点的加速度是成比例的。即梯度影响加速度,加速度影响质点的速度,速度再影响质点在山中的位置

更新形式:

v = mu * v - learning_rate * dx // 更新速度
x += v //更新位置

这里引入了一个初始化为0的变量v,和一个超参数mu,mu被看作动量(一般设置为0.9),其有效地抑制了速度,降低了系统的动能(即质点上次的速度方向会影响该次的速度方向)

mu通常设置为[0.5, 0.9, 0.95, 0.99]中的一个,动量随时间慢慢提升有时能略微改善最优化的结果

Nesterov动量:

与不同变量不同,其核心思想是,观察上文的动量公式,x会通过mu*v而稍微改变,而mu*v是在还没计算梯度之前就已经确定的,我们可以将未来的近似位置x+mu*v看作是“预测未来”,x+mu*v这个点一定在我们等会梯度下降更新后要停止的位置附近,因此,我们不妨计算x+mu*v的梯度,而不是x的梯度

如图所示,既然我们知道mu*v会把我们带到绿色箭头指向的点,我们就不在原地(红色点)计算梯度了,我们在绿色箭头所指的点计算梯度

#易于理解的实现版本
x_ahead = x + mu * v
v = mu * v - learning_rate * dx_ahead
x += v#实际实现版本
v_prev = v
v = mu * v - learning_rate * dx
x += -mu * v_prev + (1 + mu) * v

学习率退火:

在训练深度网络的时候,让学习率随着时间退火(逐渐减小)通常是有帮助的。因为如果学习率很高,系统的动能就过大,参数向量就会无规律地跳动,不能够稳定到损失函数更深更窄的局部极值去。

实现学习率退火的方式:

1.随步数衰减:

每进行几个epoch就根据一些因素降低学习率。典型的是每过5个epoch就将学习率减少一半,或者每20个epoch将学习率减少到之前的0.1,具体数字设定严重依赖于具体问题和模型。

经验做法:使用一个固定的学习率来进行训练的同时观察验证集的错误,每当验证集错误率停止下降时,就乘一个常数(例如0.5)来降低学习率

2.指数衰减:

公式为\alpha = \alpha_0e^{-kt},其中\alpha_0为初始学习率,k是超参数,t是迭代次数,也可以使用epoch

3.1/t衰减

公式为\alpha = \frac{\alpha_0}{1+kt}

在实践中,随步数衰减的dropout更受欢迎,因为它使用的超参数可解释性比k更强,若有足够的计算资源,可以让衰减更缓慢一些,让训练时间更长

逐参数适应学习率方法:

前面讨论的方法都是对学习率进行全局的操作,且对所有参数,其学习率都是一样的,下面要介绍的方法是能够适应性地根据参数来调整其对应的学习率,从而使得每个参数的学习率可能都不一样。

Adagrad:

cache += dx**2
x += -learning_rate * dx / (np.sqrt(cache) + eps)

cache与梯度矩阵size一致,跟踪了每个参数梯度的平方和,被用来归一化参数更新步长(学习率),这样一来,高梯度值的权重的学习率被减弱,低梯度值的权重的学习率被增强。平方根的操作非常重要,加入eps噪声是为了防止除0,该算法的缺点是学习率单调变小通常过于激进,且过早停止学习

RMSprop:

是Adagrad的改进

cache = decay_rate * cache + (1 - decay_rate) * dx**2
x += - learning_rate * dx / (np.sqrt(cache) + eps)

decay_rate是取值在[0.9, 0.99, 0.999]的超参,cache变成了梯度平方的滑动平均,从而使学习率不会单调变小

Adam:

m = beta1 * m + (1 - beta1) * dx
v = beta2 * v + (1 - beta2) * dx ** 2
x += - learning_rate * m / (np.sqrt(v) + eps)

这里的更新方法和RMSProp很像,但其使用的是平滑版的梯度m

超参数调优:

训练一个神经网络会遇到很多的超参数设置,常用的有:

初始学习率

学习率衰减方式

正则化强度

实现:

更大的神经网络需要更长的时间去训练,所以调参可能幻几天甚至几周。一个设计代码的思路是:

使用子程序持续地随机设置参数,然后进行最优化,训练过程中,子程序会对每个周期后验证集的准确率进行监控,然后写下一个记录点日志。还有一个主程序,他可以启动或者结束计算群中的子程序,根据筛选条件查看子程序写下的记录点,输出它们的训练统计数据,所谓海选。

比起交叉验证,最好使用一个验证集:

大多数情况下,一个size合理的验证集可以使代码更简单

超参数范围:

在对数尺度上进行超参数搜索,例如,一个典型的学习率搜索应该是这样:

learning_rate = 10**uniform(-6,1)

这是因为如果只采取固定的线性步长分布的话,当学习率很小或者很大的话,步长对学习率的相对改变量差异是巨大的,所以我们采取对数尺度。但对于一些特别的参数(比如dropout),我们还是采取在原始尺度上搜索(dropout = uniform(0,1))

随机搜索优于网络搜索:

通常有部分超参数比其他超参数更重要,通过随机化搜索,而不是网格化搜索,可以更精确地发现较重要的超参数的好数值

对于边界上的最优值要谨慎:

这种情况一般发生在搜索范围不好的情况,若我们得到的超参数较优值在搜索边界上,我们就需要调整我们的搜索范围

从粗到细地分阶段搜索:

可以先进行粗略的范围搜索,然后根据最优值出现的地方,缩小范围进行搜索。进行粗搜索的时候,训练一个epoch就可以了,因为很多超参数的设定会让模型无法学习。搜索的范围越精细,训练的epoch越多

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

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

相关文章

IntelliJ IDEA 中左上方未显示项目根目录问题

问题: 在IDEA中编写代码时,发现左上方只显示项目的子模块,未显示根项目名称。 如图所示,未显示子模块的根项目:问题分析 顶层根目录未被识别为项目根目录,需要手动添加识别。 问题解决 进入File – Project…

OpenCV 图像变换全解析:从镜像翻转到仿射变换的实践指南

前言处理图像时,翻转、旋转、平移等操作很常用。OpenCV 提供了简单的方法实现这些变换,本文带你快速学会用它做图像翻转和仿射变换。1 图像翻转(图像镜像旋转)在OpenCV中,图片的镜像旋转是以图像的中心为原点进行镜像翻转的。cv2.flip(img,fl…

【运维】Linux运维命令记录

重置root密码使用命令重新设置一下root账户的密码 passwd root根据提示设置一下密码,然后使用sudo -i 时输入密码就可以切换到root账户了ssh登陆以后,要用sudo -i命令给用户提权,提到超级管理员,然后输入密码才有用

PandasAI连接LLM进行智能数据分析

1. 引言 Pandas是一个数据分析开源组件库,提供了高性能、易用的数据结构和数据分析工具。它的核心的功能是其DataFrame对象,这是一个带有行和列标签的二维表格数据结构,支持缺失数据处理、时间序列功能、灵活的数据输入输出方法、数据对齐和…

Spring之【Bean的生命周期】

目录 1、生成BeanDefinition BeanDefinitionRegistry接口 DefaultListableBeanFactory实现类 2、合并BeanDefnition AbstractBeanFactory类 3、BeanFactoryPostProcessor的方法回调 AbstractApplicationContext类 PostProcessorRegistrationDelegate类 4、BeanPostPro…

搜狐新闻直播间适配HarmonyOs实现点赞动画

01背景介绍随着新闻客户端鸿蒙单框架系统适配工作的推进,从原来的基础功能到现在已经适配全功能的85%以上。与此同时,我们也在持续深入挖掘鸿蒙系统的特性,以提升整体应用的质量与用户体验。在这一过程中,动画作为增强交互与视觉体…

83、设置有人DTU设备USR-M100采集传感器数据,然后上传阿里云服务

基本思想:设置M100 采集传感器数据 一、首先将DTU设备USR-M100连接路由器上,然后使用python代码搜索同一局域网设备, import platform import sys import os import time import threadinglive_ip = 0def get_os():os = platform.system()if os == "Windows":re…

P1019 [NOIP 2000 提高组] 单词接龙

题目描述单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时&#…

详解力扣高频SQL50题之1633. 各赛事的用户注册率【简单】

传送门:1633. 各赛事的用户注册率 题目 用户表: Users -------------------- | Column Name | Type | -------------------- | user_id | int | | user_name | varchar | -------------------- user_id 是该表的主键(具有唯一值的列)。 该表中的每行包…

FROM stakater/java8-alpine 构建cocker镜像

在 Dockerfile 中,FROM stakater/java8-alpine 是第一条也是最核心的指令,它定义了构建新镜像所基于的「基础镜像」。以下是逐层解析:🔍 关键字拆解 1. FROM —— 起点指令 ✅ 作用:声明当前镜像的起点(父镜…

Word2Vec模型训练全流程解析:从数据预处理到实体识别应用

请添加图片描述 训练Word2Vec模型 概述 问题 我们如何训练Word2Vec模型?在特定数据集上训练Word2Vec模型何时是有利的? 目标 理解在自有数据上训练Word2Vec模型而非使用预训练模型的优势 Colab环境配置 运行以下代码以启用辅助函数并重新读取数据…

在Ubuntu上使用QEMU学习RISC-V程序(2)gdb调试

文章目录一、准备工作二、基本调试流程1. 设置断点2. 执行程序3. 查看源代码/汇编三、查看寄存器1. 查看通用寄存器2. 查看特殊寄存器四、查看内存1. 内存查看命令2. 内存修改命令五、调试实战示例六、高级调试技巧1. 条件断点2. 自动显示3. 内存断点(观察点&#x…

不止于“亮”:一盏智慧路灯的技术进化史——塔能科技用“落地性”定义行业标准

在凌晨3点的园区道路之上,路灯会随着车辆的靠近而自动亮起,待车辆逐渐远去之后,又会缓缓地调暗下来;当电缆意外被触碰的时候,系统能够在短短3秒之内自动发出报警信息,并且推送出维修工单;而当一…

Redis的String数据类型底层实现

redis就是用c语言写,但redis的string并没有直接用c语言的string,而是自己搞了一个 SDS 结构体来表示字符串。SDS 的全称是 Simple Dynamic String,中文叫做“简单动态字符串”。想知道为什么这么做,我们先看看c语言的string是什么…

【音视频学习】四、深入解析视频技术中的YUV数据存储方式:从原理到实践

文章目录 引言 1. YUV 基础:为什么它比 RGB 更适合视频? 1.1 YUV 与 RGB 的核心区别 1.2 YUV色度下采样简介 2. YUV 的三大存储方式 方式一:平面格式(Planar) 方式二:半平面格式(Semi-Planar ) 方式三:打包格式(Packed YUV) 三种存储方式对比: 3. 如何选择合适的 Y…

前端项目组成

一、前端项目常见模块及功能(以 Vue/React 通用结构为例) 前端项目的模块本质是「按功能拆分的代码文件/文件夹」,就像盖房子的「砖、梁、窗」各司其职:模块类型功能说明(大白话)举个例子pages(…

聚观早报 | 猿编程推动中美青少年AI实践;华为Pura 80数字版售价公布;iPhone 17 Air电池曝光

聚观早报每日整理最值得关注的行业重点事件,帮助大家及时了解最新行业动态,每日读报,就读聚观365资讯简报。整理丨肖羽7月24日消息猿编程推动中美青少年AI实践华为Pura 80数字版售价公布iPhone 17 Air电池曝光亚马逊收购AI初创公司Bee蜂巢半固…

unittest 案例执行顺序详解

unittest 案例执行顺序详解在 unittest 框架中,测试用例的执行顺序有默认规则,也可通过自定义方式调整。以下是具体说明:一、默认执行顺序规则unittest 对测试用例的执行顺序遵循 “按测试方法名的 ASCII 码排序” 原则,具体逻辑如…

【web大前端】001_前端开发入门:创建你的第一个网页

前端开发入门:创建你的第一个网页 在当今数字化时代,网页已经成为人们获取信息和交流的重要平台。对于想要学习编程的人来说,前端开发往往是一个不错的起点。本文将带你通过简单的两步,创建属于你的第一个网页程序。 点击这里去…

HTTP性能优化终极指南:从协议原理到企业级实践

前言:为什么性能优化是Web开发的生命线?根据Google研究数据,当页面加载时间从1秒增加到3秒时,跳出率提升32%;当达到5秒时,转化率下降90%。本文将通过七层优化体系,带您掌握HTTP性能优化的核心技…