诸神缄默不语-个人CSDN博文目录
(如果只想看代码,请直接跳到“方法”一节,开头我介绍我的常用方法,后面介绍具体的各种方案)
神经网络通过多层神经元相互连接构成,而这些连接的强度就是通过权重(Weight)来表征的。权重是可训练的参数,意味着它们会在训练过程中根据反向传播算法自动调整,以最小化网络的损失函数。
每个神经元接收到的输入信号会与相应的权重相乘,然后所有这些乘积会被累加在一起,最后可能还会加上一个偏置项(Bias),形成该神经元的净输入。这个净输入随后会被送入激活函数,产生神经元的输出,进而传递给下一层的神经元。在这个过程中,权重决定了信号传递的强度和方向,是调整和控制网络学习过程的关键。
从数学角度看,权重可以被组织成矩阵或张量的形式,以支持高效的矩阵运算和便于处理来自网络上一层的所有输入及其对下一层的影响。训练开始时,权重通常会被初始化为小的随机值,这是为了打破对称性并允许网络学习。随着训练的进行,通过梯度下降算法等优化方法,权重会逐渐调整,以使得网络的预测输出尽可能接近真实标签。
总之,神经网络的权重是连接网络中各层之间的桥梁,它们的值决定了网络的行为和性能,通过训练不断优化这些权重,神经网络能够学习到复杂的数据表示和模式,完成各种复杂的任务。
在深度学习中,神经网络的权重初始化对模型的训练效率和最终性能有着至关重要的影响。适当的初始化方法可以帮助加速收敛,避免陷入局部最小值,同时也可以防止训练过程中的梯度消失或梯度爆炸问题。相反,不当的权重初始化可能导致模型训练效果不佳,甚至无法收敛。
我个人的习惯是在构建模型的时候直接对需要手写的权重进行初始化。权重用Xavier初始化,偏置直接初始化为全0向量,代码示例:
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中的权重进行初始化的。如果你们需要改成对特定参数进行初始化的话也好改,反正你们懂这个意思就行。
Uniform 高斯分布初始化
公式:权重 w ∼ N ( 0 , stdev 2 ) w \sim \mathcal{N}(0, \text{stdev}^2) w∼N(0,stdev2)
概述:最简单的方法是从某个分布(通常是均匀分布或正态分布)中随机选取权重值。
代码实例:
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)
公式:权重 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)
对梯度消失问题有优势。
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)
Kaiming Normal(也称为He Normal)初始化是由何凯明等人在2015年提出的一种权重初始化方法,旨在解决ReLU激活函数在深度神经网络中使用时的梯度消失或爆炸问题。这种方法考虑到了ReLU激活函数特性,特别是其非零区域的分布特点,从而提出通过调整初始化权重的方差来保持信号在前向传播和反向传播过程中的稳定。
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)
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
对权重矩阵进行奇异值分解,然后根据分解结果来重构权重矩阵。以下是一个简化的示例:
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初始化提供了一种灵活的方法来控制神经网络权重的特性,尤其是在需要维护输入特征结构或优化训练稳定性的高级应用中。通过精确控制权重矩阵的奇异值,研究者和工程师可以优化网络的初始化状态,从而提高模型训练的效率和效果。然而,由于其实现相对复杂,通常仅在特定需求下采用此方法。
权重初始化在神经网络训练中起着决定性的作用。选择合适的初始化方法可以显著提高训
练效率和模型性能。在实践中,应根据模型的具体结构和使用的激活函数来选择最适合的初始化方法。以上提到的方法仅是众多初始化技术中的几种,研究者和开发者可以根据需要选择或创新更适合自己模型需求的初始化策略。