初始化神经网络权重的方法总结 神经网络如果权重全部初始化为0会存在什么问题
ztj100 2024-12-18 18:19 25 浏览 0 评论
在本文中,评估了权值初始化的许多方法和当前的最佳实践
零初始化
将权值初始化为零是不行的。那我为什么在这里提到它呢?要理解权值初始化的需要,我们需要理解为什么将权值初始化为零是无效的。
让我们考虑一个类似于上面所示的简单网络。每个输入只是一个标量X?,X?X?。和每个神经元的权重是W?和W?。每次权重更新如下:
Out? = X?W? + X?W? + X?W?
Out? = X?W? + X?W? + X?*W?
正如你所看到的现在,如果权重矩阵W = [W?W?]被初始化为零,然后out1和out2都完全一样。
即使我们对两者都添加一个非零的随机偏差项,权值也会更新为非零,但它们仍将保持相同,因此隐藏单元的两个神经元都在计算相同的东西。换句话说,它们是对称的。
这是非常不可取的,因为这是浪费计算。这就是零初始化无法工作的原因。
随机初始化
现在我们知道权重必须是不同的,下一个想法是随机初始化这些权重。随机初始化比零初始化好得多,但是这些随机数可以是任意数吗?
假设你使用的是s型非线性。sigmoid函数如下所示。
我们可以看到,对于大到6的值,sigmoid的值几乎是1,对于小到-6的值,sigmoid的值为0。这意味着如果我们的权值矩阵被初始化为过大或过小的值,所有有用的信息都会在sigmoid函数中丢失。
如果我们使用ReLu非线性,这就不那么重要了,但是在将权重初始化为大值或小值时还有其他问题。有更好的方法来初始化权重。
Xavier初始化
Xavier初始化是由Xavier Glorot和Yoshua Bengio在2010年提出的。本文的主要目标是初始化权重,使激活的平均值为零,标准偏差为1。考虑如下所示计算的函数。
Z = WX + b
这里W是权值矩阵,X是来自前一层的输入,b是偏差。Z是一个层计算的输出,也称为激活。我们希望Z的均值是0,标准差是1。(从技术上讲,Z是ReLu等非线性激活后的结果)
为什么均值为0,标准差为1这么重要?
考虑一个有100层的深度神经网络。在每一步,权重矩阵乘以来自前一层的激活。如果每一层的激活大于1,当它们被重复乘以100次时,它们就会不断变大,爆炸到无穷大。类似地,如果激活值小于1,它们将消失为零。这叫做渐变爆炸和渐变消失问题。 我们可以从下图中看到这一点。甚至比1稍大一点的值也会爆炸成非常大的数字,而比1稍小一点的值也会消失为零。
为了避免梯度和激活的爆炸和消失,我们希望激活的平均值为0,标准偏差为1。我们可以通过仔细选择权重来实现这一点。
在本文发布期间,权值的最佳实践是从均匀分布[-1,1]中随机选取,然后除以输入维数的平方根。事实证明,这不是一个好主意,梯度消失了,如果可能的话,训练也非常缓慢。
这个问题通过Xavier的初始化得到了解决,Xavier的初始化建议我们从一个均匀分布中随机初始化权重,如下图所示。
Xavier 初始化的 Uniform分布
现在,Xavier的初始化是通过从标准正态分布中选择权重来完成的,每个元素都要除以输入维度大小的平方根。在PyTorch中,代码如下所示。
torch.randn(n_inp, n_out)*math.sqrt(1/n_inp)
Xavier的初始化工作相当好,对于对称非线性,如sigmoid和Tanh。然而,对于目前最常用的非线性函数ReLu,它的工作效果并不理想。
Kaiming 初始化
2015年,何凯明等人撰写了一篇名为《Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification》的论文,在论文中,他们介绍了现在广为人知的Kaiming 初始化。
但是为什么我们需要Kaiming 初始话呢?关于ReLu非线性的Xavier Init有什么问题?
从上图中可以看出,ReLu对所有X<0给出了0,对所有X>给出了Y=X。ReLu并没有很好地定义0,但大多数程序都将其赋值为接近于0的近似,比如machine epsilon。
左:均值0,标准差1的正态分布。右:通过ReLu后的正态分布。
在上面我们可以看到2个散点图,左边是ReLu之前的数据,右边是ReLu之后的数据。从图像中可以清楚地看到,在ReLu之后,方差几乎是一半,平均值略高。这改变了激活,方差减少了一半,所以我们需要将方差加倍才能得到Xavier Init的原始效果。因此,我们将权重乘以一个额外的值√2。所以在PyTorch中,Kaiming 初始化如下所示。
torch.randn(n_inp, n_out)*math.sqrt(2/n_inp)
如果你仍然对上面的公式不太理解,那么记住:
方差=标准差的平方
方差翻倍所以需要乘以√2
Fixup初始化
Fixup是Zhang等人在2019年提出的初始化。根据他们的观察,Kaiming 的初始化和其他标准的初始化不能很好地用于有残差分支的网络(又叫残差网络)。他们发现,标准初始化的残差网络只有在BatchNorm下才能正常工作。
让我们看看为什么Kaiming Init不能在残差网络上更好的工作。考虑如下图所示的跳过连接。X2 = f(X1) X3 = f(X2) + X1。我们知道Kaiming init选择的权重使得每一层后的激活有0均值和1方差。我们知道X1的方差是1 X2的方差是1。但是Kaiming init不考虑跳过连接。因此,根据总方差定律,X3的方差翻倍。由残差分支添加的额外方差在Kaiming Init中没有考虑在内。因此残差网络不能很好地与标准初始化一起工作,除非它们有BatchNorm。没有BatchNorm,输出方差会随深度呈指数爆炸式增长。
Var[X???] ≈ 2Var[X? ]
残差网络中的跳过连接
该论文的作者提出了一个重要的观察结果,即SGD更新每个残差分支的权重会在高度相关的方向上更新网络输出。 这意味着,如果所有残差分支权重都由X更新,则网络输出也将在相同的权重更新方向上按比例地更改为X。
作者将所需的网络输出变化定义为Θ(η)。 如我们所知,平均每个残差分支对输出更新的贡献均等。如果我们称残差分支的数量为L,则每个残差分支平均应将输出改变Θ(η/ L),以实现总变化。 输出上的Θ(η)。
接下来,作者展示如何初始化m层的残差分支,以便SGD更新将输出更改Θ(η/ L)。 作者表明,可以通过以下方式重新调整这些权重层的标准初始化:
权重比例因子
作者还讨论了偏差和乘数的效用。 他们发现在每次卷积,添加一个初始值为0的偏置层,线性层和逐元素激活导致训练显着改善之前。 他们还发现,在每个残差分支上添加一个乘法标度有助于通过标准化来模仿网络的权重范数动态。
所以所有的而解决方案汇总如下
LSUV初始化
Mishkin等人在2016年的一篇论文《All you need is a good Init》中介绍了LSUV。LSUV Init是一种数据驱动的方法,它具有最小的计算量和非常低的计算开销。初始化是一个2部分的过程,首先初始化标准正交矩阵的权值(与高斯噪声相反,它只是近似正交)。下一部分是迭代一个小批处理并缩放权重,以便激活的方差为1。作者断言,在大范围内,小批量大小对方差的影响可以忽略不计。
在论文中,作者列出了以下初始化步骤。
1. 使用单位方差将权重初始化为高斯噪声。
1. 使用SVD或QR将它们分解为正交坐标。
1. 使用第一个微型批处理在网络中进行迭代,并在每次迭代比例时权重以使输出方差接近1。重复直到输出方差为1或发生最大迭代。
论文中,作者提出比例因子为√Var(BL),其中BL —它的输出Blob
作者还提出了最大迭代次数的值,以防止无限循环。但是,在他们的实验中,他们发现在1–5次迭代中实现了单位方差。
可以将LSUV Init看作是正交初始化和BatchNorm的组合,它仅在第一个迷你批处理中执行。 作者在实验中表明,与完整的BatchNorm相比,该方法在计算上非常高效。
转移学习
转移学习是一种在我们的新模型中使用已经训练有素的模型进行权重的方法,该模型已经针对相似的任务进行了训练。 这些权重已经学习了很多有用的信息,我们可以针对我们的特定目标进行微调! 我们有一个了不起的模型,没有初始化的麻烦。
每次使用来自另一个模型的预训练权重都是最好的方法。唯一需要我们自己初始化权值的情况是,我们在一个从未有人训练过的网络上工作。在大多数实际情况下,情况并非如此,所以一般情况下,我们使用一个与训练的模型作为我们训练的开始是一个很好的习惯。
作者 Akash Shastri
deephub翻译组
相关推荐
-
- SpringBoot如何实现优雅的参数校验
-
平常业务中肯定少不了校验,如果我们把大量的校验代码夹杂到业务中,肯定是不优雅的,对于一些简单的校验,我们可以使用java为我们提供的api进行处理,同时对于一些...
-
2025-05-11 19:46 ztj100
- Java中的空指针怎么处理?
-
#暑期创作大赛#Java程序员工作中遇到最多的错误就是空指针异常,无论你多么细心,一不留神就从代码的某个地方冒出NullPointerException,令人头疼。...
- 一坨一坨 if/else 参数校验,被 SpringBoot 参数校验组件整干净了
-
来源:https://mp.weixin.qq.com/s/ZVOiT-_C3f-g7aj3760Q-g...
- 用了这两款插件,同事再也不说我代码写的烂了
-
同事:你的代码写的不行啊,不够规范啊。我:我写的代码怎么可能不规范,不要胡说。于是同事打开我的IDEA,安装了一个插件,然后执行了一下,规范不规范,看报告吧。这可怎么是好,这玩意竟然给我挑出来这么...
- SpringBoot中6种拦截器使用场景
-
SpringBoot中6种拦截器使用场景,下面是思维导图详细总结一、拦截器基础...
- 用注解进行参数校验,spring validation介绍、使用、实现原理分析
-
springvalidation是什么在平时的需求开发中,经常会有参数校验的需求,比如一个接收用户注册请求的接口,要校验用户传入的用户名不能为空、用户名长度不超过20个字符、传入的手机号是合法的手机...
- 快速上手:SpringBoot自定义请求参数校验
-
作者:UncleChen来源:http://unclechen.github.io/最近在工作中遇到写一些API,这些API的请求参数非常多,嵌套也非常复杂,如果参数的校验代码全部都手动去实现,写起来...
- 分布式微服务架构组件
-
1、服务发现-Nacos服务发现、配置管理、服务治理及管理,同类产品还有ZooKeeper、Eureka、Consulhttps://nacos.io/zh-cn/docs/what-is-nacos...
- 优雅的参数校验,告别冗余if-else
-
一、参数校验简介...
- Spring Boot断言深度指南:用断言机制为代码构筑健壮防线
-
在SpringBoot开发中,断言(Assert)如同代码的"体检医生",能在上线前精准捕捉业务逻辑漏洞。本文将结合企业级实践,解析如何通过断言机制实现代码自检、异常预警与性能优化三...
- 如何在项目中优雅的校验参数
-
本文看点前言验证数据是贯穿所有应用程序层(从表示层到持久层)的常见任务。通常在每一层实现相同的验证逻辑,这既费时又容易出错。为了避免重复这些验证,开发人员经常将验证逻辑直接捆绑到域模型中,将域类与验证...
- SpingBoot项目使用@Validated和@Valid参数校验
-
一、什么是参数校验?我们在后端开发中,经常遇到的一个问题就是入参校验。简单来说就是对一个方法入参的参数进行校验,看是否符合我们的要求。比如入参要求是一个金额,你前端没做限制,用户随便过来一个负数,或者...
- 28个验证注解,通过业务案例让你精通Java数据校验(收藏篇)
-
在现代软件开发中,数据验证是确保应用程序健壮性和可靠性的关键环节。JavaBeanValidation(JSR380)作为一个功能强大的规范,为我们提供了一套全面的注解工具集,这些注解能够帮...
- Springboot @NotBlank参数校验失效汇总
-
有时候明明一个微服务里的@Validated和@NotBlank用的好好的,但就是另一个里不能用,这时候问题是最不好排查的,下面列举了各种失效情况的汇总,供各位参考:1、版本问题springbo...
- 这可能是最全面的Spring面试八股文了
-
Spring是什么?Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)