(如果只想看代码,请直接跳到"方法"一节,开头我介绍我的常用方法,后面介绍具体的各种方案)
神经网络通过多层神经元相互连接构成,而这些连接的强度就是通过权重(Weight)来表征的。权重是可训练的参数,意味着它们会在训练过程中根据反向传播算法自动调整,以最小化网络的损失函数。
每个神经元接收到的输入信号会与相应的权重相乘,然后所有这些乘积会被累加在一起,最后可能还会加上一个偏置项(Bias),形成该神经元的净输入。这个净输入随后会被送入激活函数,产生神经元的输出,进而传递给下一层的神经元。在这个过程中,权重决定了信号传递的强度和方向,是调整和控制网络学习过程的关键。
从数学角度看,权重可以被组织成矩阵或张量的形式,以支持高效的矩阵运算和便于处理来自网络上一层的所有输入及其对下一层的影响。训练开始时,权重通常会被初始化为小的随机值,这是为了打破对称性并允许网络学习。随着训练的进行,通过梯度下降算法等优化方法,权重会逐渐调整,以使得网络的预测输出尽可能接近真实标签。
总之,神经网络的权重是连接网络中各层之间的桥梁,它们的值决定了网络的行为和性能,通过训练不断优化这些权重,神经网络能够学习到复杂的数据表示和模式,完成各种复杂的任务。
在深度学习中,神经网络的权重初始化对模型的训练效率和最终性能有着至关重要的影响。适当的初始化方法可以帮助加速收敛,避免陷入局部最小值,同时也可以防止训练过程中的梯度消失或梯度爆炸问题。相反,不当的权重初始化可能导致模型训练效果不佳,甚至无法收敛。
文章目录
- 权重初始化的必要性
- 不认真对待的危害
- 权重初始化方法
-
- [1. 随机初始化](#1. 随机初始化)
- [2. Xavier/Glorot 初始化](#2. Xavier/Glorot 初始化)
- [3. He/Kaiming 初始化](#3. He/Kaiming 初始化)
- [4. SVD 初始化](#4. SVD 初始化)
- 结论
- 本文撰写过程中使用到的其他参考资料
权重初始化的必要性
- 加速收敛:合适的初始化方法能够使神经网络更快地收敛到较低的误差。
- 避免梯度问题:通过控制权重的初始范围,可以帮助避免训练过程中的梯度消失或爆炸问题。
- 影响泛化能力:初始化不仅影响训练速度和稳定性,也间接影响模型的泛化能力。
不认真对待的危害
- 训练时间延长:不合适的初始化可能导致模型需要更长的时间来收敛。
- 性能下降:极端情况下,不合适的初始化会导致模型无法从训练数据中学习有效的特征,从而严重影响模型性能。
- 训练失败:在某些情况下,错误的初始化方法甚至会导致训练完全失败(例如,梯度消失或爆炸)。
权重初始化方法
我个人的习惯是在构建模型的时候直接对需要手写的权重进行初始化。权重用Xavier初始化,偏置直接初始化为全0向量,代码示例:
python
from torch.nn.init import xavier_normal_
class MPBFNDecoder(nn.Module):
def __init__(self):
super(MPBFNDecoder,self).__init__()
...
self.Wf12=nn.Parameter(xavier_normal_(torch.empty(charge_num,ds)))
self.Wf13=nn.Parameter(xavier_normal_(torch.empty(penalty_num,ds)))
self.Wf23=nn.Parameter(xavier_normal_(torch.empty(penalty_num,ds)))
self.b12=nn.Parameter(torch.zeros(charge_num,))
self.b13=nn.Parameter(torch.zeros(penalty_num,))
self.b23=nn.Parameter(torch.zeros(penalty_num,))
完整代码见https://github.com/PolarisRisingWar/LJP_Collection/blob/master/models/MPBFN/train_and_test.py
PyTorch内置的模型都已经自动写好了初始化函数,不需要手动设置。
以下有些代码示例是指定Linear中的权重进行初始化的。如果你们需要改成对特定参数进行初始化的话也好改,反正你们懂这个意思就行。
1. 随机初始化
Uniform 高斯分布初始化
-
公式 :权重 w ∼ N ( 0 , stdev 2 ) w \sim \mathcal{N}(0, \text{stdev}^2) w∼N(0,stdev2)
- 其中, N ( 0 , stdev 2 ) \mathcal{N}(0, \text{stdev}^2) N(0,stdev2) 表示均值为0,标准差为 stdev \text{stdev} stdev 的高斯(正态)分布。
-
概述:最简单的方法是从某个分布(通常是均匀分布或正态分布)中随机选取权重值。
-
代码实例:
python
import torch
import torch.nn as nn
# 均匀分布初始化
def uniform_init(model):
if isinstance(model, nn.Linear):
nn.init.uniform_(model.weight, -1, 1)
if model.bias is not None:
nn.init.constant_(model.bias, 0)
# 正态分布初始化
def normal_init(model):
if isinstance(model, nn.Linear):
nn.init.normal_(model.weight, mean=0, std=1)
if model.bias is not None:
nn.init.constant_(model.bias, 0)
2. Xavier/Glorot 初始化
公式 :权重 w ∼ U ( − 6 n in + n out , 6 n in + n out ) w \sim \mathcal{U}(-\sqrt{\frac{6}{n_{\text{in}} + n_{\text{out}}}}, \sqrt{\frac{6}{n_{\text{in}} + n_{\text{out}}}}) w∼U(−nin+nout6 ,nin+nout6 )
- 其中, U ( a , b ) \mathcal{U}(a, b) U(a,b) 表示均匀分布, n in n_{\text{in}} nin 是层输入的单元数, n out n_{\text{out}} nout 是层输出的单元数。
对梯度消失问题有优势。
- 论文 :(2010 PMLR) Understanding the difficulty of training deep feedforward neural networks
- 原理:考虑到输入和输出的方差,目的是保持所有层的梯度大小大致相同。
- 代码实例:
python
def xavier_init(model):
if isinstance(model, nn.Linear):
nn.init.xavier_uniform_(model.weight)
if model.bias is not None:
nn.init.constant_(model.bias, 0)
3. He/Kaiming 初始化
- 公式 :权重 w ∼ N ( 0 , 2 n in ) w \sim \mathcal{N}(0, \frac{2}{n_{\text{in}}}) w∼N(0,nin2)
- 其中, n in n_{\text{in}} nin 是层输入的单元数,假设权重初始化为均值为0,方差为 2 n in \frac{2}{n_{\text{in}}} nin2 的正态分布。
Kaiming Normal(也称为He Normal)初始化是由何凯明等人在2015年提出的一种权重初始化方法,旨在解决ReLU激活函数在深度神经网络中使用时的梯度消失或爆炸问题。这种方法考虑到了ReLU激活函数特性,特别是其非零区域的分布特点,从而提出通过调整初始化权重的方差来保持信号在前向传播和反向传播过程中的稳定。
- 论文 :(2015 ICCV) Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification
- 原理 :Kaiming Normal 初始化的核心思想是根据网络层的输入单元数量(即fan_in)来调整权重的方差,确保各层激活值的方差保持一致,以此来避免在深层网络中出现梯度消失或爆炸的问题。具体来说,该方法建议将权重初始化为均值为0,方差为 2 / fan_in 2/\text{fan\_in} 2/fan_in的正态分布,其中 fan_in \text{fan\_in} fan_in是权重矩阵中输入单元的数量。
- 代码实例:
python
def he_init(model):
if isinstance(model, nn.Linear):
nn.init.kaiming_uniform_(model.weight, mode='fan_in', nonlinearity='relu')
if model.bias is not None:
nn.init.constant_(model.bias, 0)
4. SVD 初始化
- 公式:无特定公式。SVD 初始化涉及对权重矩阵进行奇异值分解(SVD),然后根据需要重新组合以初始化网络权重。
SVD(奇异值分解)初始化是一种高级权重初始化技术,它通过对权重矩阵应用奇异值分解来初始化神经网络。这种方法特别适用于需要保持输入数据特征或处理特定矩阵结构(如正交性或特定范数)的场合。
对RNN有比较好的效果。参考论文:(2014 ICLR) Exact solutions to the nonlinear dynamics of learning in deep linear neural networks
SVD 初始化的基本思想是将权重矩阵 W W W 分解为三个矩阵的乘积: W = U Σ V T W = U\Sigma V^T W=UΣVT,其中 U U U 和 V V V 是正交矩阵, Σ \Sigma Σ 是对角矩阵,包含 W W W 的奇异值。初始化过程中,可以通过调整 Σ \Sigma Σ 中的奇异值来控制权重矩阵的性质,如其范数或分布特性,从而影响模型的训练动态和最终性能。
代码实例
在PyTorch中实现SVD初始化可能涉及到使用torch.svd
对权重矩阵进行奇异值分解,然后根据分解结果来重构权重矩阵。以下是一个简化的示例:
python
import torch
import torch.nn as nn
def svd_init(model):
if isinstance(model, nn.Linear):
U, S, V = torch.svd(torch.randn(model.weight.shape))
# 可以根据需要调整S中的奇异值
model.weight.data = torch.mm(U, torch.mm(torch.diag(S), V.t()))
if model.bias is not None:
nn.init.constant_(model.bias, 0)
SVD初始化提供了一种灵活的方法来控制神经网络权重的特性,尤其是在需要维护输入特征结构或优化训练稳定性的高级应用中。通过精确控制权重矩阵的奇异值,研究者和工程师可以优化网络的初始化状态,从而提高模型训练的效率和效果。然而,由于其实现相对复杂,通常仅在特定需求下采用此方法。
结论
权重初始化在神经网络训练中起着决定性的作用。选择合适的初始化方法可以显著提高训
练效率和模型性能。在实践中,应根据模型的具体结构和使用的激活函数来选择最适合的初始化方法。以上提到的方法仅是众多初始化技术中的几种,研究者和开发者可以根据需要选择或创新更适合自己模型需求的初始化策略。