🧠 神经网络参数初始化深度指南

初始化是确保深度学习模型高效训练和稳定收敛的关键步骤。

🚀 为什么初始化很重要

不合适的初始化会导致:

  • 训练收敛极慢。
  • 梯度消失/爆炸。
  • 对称破坏失败(不同神经元学不到不同特征)。

好的初始化尽量保持前向激活反向梯度的方差在合适范围(既不爆也不灭),帮助深层网络稳定训练。

🧠 基本概念与禁忌

常用术语

  • fan-infan\text{-}infan-in: 该层输入通道数(前一层神经元数)。
  • fan-outfan\text{-}outfan-out: 该层输出通道数(当前层神经元数)。
  • gaingaingain: 与激活函数相关的放大系数(用于调整方差)。
    • 常用 gaingaingain: ReLU→2\text{ReLU} \to \sqrt{2}ReLU2 tanh⁡/sigmoid→1\tanh/\text{sigmoid} \to 1tanh/sigmoid1linear→1\text{linear} \to 1linear1LeakyReLU(α)→2/(1+α2)\text{LeakyReLU}(\alpha) \to \sqrt{2/(1+\alpha^2)}LeakyReLU(α)2/(1+α2)
  • 目标(直觉): 初始化使得每层输出的方差 ≈\approx 每层输入的方差(方差守恒/稳定传播)。

🔴 禁忌(先说不要做的)

  • 所有权重都设为 000 →\to 每个神经元梯度相同,无法打破对称性。
  • 随意极大/极小值 →\to 导致梯度爆炸或消失。
  • 忽视激活函数与网络深度的匹配。

🛠 常见初始化方法(逐个解释 + 公式 + 适用场景)

1) 随机正态 / 均匀(基础)

  • 方法: 从 N(0,σ2)\mathcal{N}(0,\sigma^2)N(0,σ2)Uniform(−a,a)\mathrm{Uniform}(-a,a)Uniform(a,a) 采样。
  • 选法: 若无经验,可先小方差正态(如 σ=0.01\sigma=0.01σ=0.01)或 Uniform(−0.1,0.1)\mathrm{Uniform}(-0.1,0.1)Uniform(0.1,0.1)
  • 优点: 简单。
  • 缺点: 深层网络易梯度问题;需要手工调方差。
  • PyTorch:
    nn.init.normal_(layer.weight, mean=0.0, std=0.01)
    nn.init.uniform_(layer.weight, -0.1, 0.1)
    

2) Xavier / Glorot 初始化(适用于 Tanh/Sigmoid)

  • 目标: 让前向传播与反向传播时各层方差接近不变(适合对称的激活如 tanh⁡\tanhtanhsigmoid\text{sigmoid}sigmoid)。
  • 均匀版本(Glorot Uniform)公式:
    a=6fan_in+fan_out,W∼U(−a,a)a = \sqrt{\frac{6}{\text{fan\_in} + \text{fan\_out}}},\quad W\sim U(-a,a)a=fan_in+fan_out6 ,WU(a,a)
  • 正态版本(Glorot Normal)公式:
    σ=2fan_in+fan_out,W∼N(0,σ2)\sigma = \sqrt{\frac{2}{\text{fan\_in} + \text{fan\_out}}},\quad W\sim\mathcal{N}(0,\sigma^2)σ=fan_in+fan_out2 ,WN(0,σ2)
  • 何时用: tanh⁡\tanhtanhsigmoid\text{sigmoid}sigmoid、线性层。也作为通用基线。
  • PyTorch:
    nn.init.xavier_uniform_(layer.weight, gain=nn.init.calculate_gain('tanh'))
    nn.init.xavier_normal_(layer.weight, gain=1.0)
    
  • 优点: 理论基础强,常用且稳定。
  • 缺点: 对于 ReLU 类激活不是最优(虽然通常可用)。

3) He / Kaiming 初始化(为 ReLU 系列设计)

  • 目标: 适应 ReLU(将负半轴截断导致有效 fanfanfan 减半),保持方差稳定。
  • 正态(Kaiming Normal)公式:
    σ=2fan_in,W∼N(0,σ2)\sigma = \sqrt{\frac{2}{\text{fan\_in}}},\quad W\sim\mathcal{N}(0,\sigma^2)σ=fan_in2 ,WN(0,σ2)
  • 均匀(Kaiming Uniform)公式:
    a=6fan_ina = \sqrt{\frac{6}{\text{fan\_in}}}a=fan_in6
  • 带 gain: 若使用 LeakyReLU、ELU 等,可传入 gain = nn.init.calculate_gain('leaky_relu', param)
  • 何时用: ReLU / LeakyReLU / variants(CNN、深层网络默认首选)。
  • PyTorch:
    nn.init.kaiming_normal_(layer.weight, a=0, mode='fan_in', nonlinearity='relu')
    # a=0 对应标准 ReLU
    
  • 优点: 在 ReLU 网络中非常有效,减少梯度消失。
  • 缺点: 如果 activation 与假设不符(例如 sigmoid),表现不佳。

4) LeCun 初始化(用于 SELU / 自归一化网络)

  • 思想: 针对 SELU 激活优化(self-normalizing nets)。
  • 公式(正态):
    σ=1fan_in\sigma = \sqrt{\frac{1}{\text{fan\_in}}}σ=fan_in1
  • 何时用: SELU 激活与 “AlphaDropout” 场景。
  • PyTorch: 可用 nn.init.kaiming_uniform_gaingaingain 与常数需设置为 LeCun 对应值或自行实现。

5) Orthogonal(正交初始化)

  • 方法: 将权重初始化为一个正交矩阵(对方差传播有好处)。
  • 优点: 对深层线性/循环网络(RNN/LSTM)有时能稳定训练,能保持激活能量。
  • 缺点: 仅适用于方阵或能 reshape 的矩阵;对卷积层不总是直观。
  • PyTorch:
    nn.init.orthogonal_(layer.weight, gain=1.0)
    

6) Sparse 初始化(稀疏)

  • 方法: 每行只保留 kkk 个非零(随机),其余置零,非零值可正态采样。
  • 用途: 大规模线性模型中,用于节省连接或模拟稀疏结构。
  • PyTorch:
    nn.init.sparse_(layer.weight, sparsity=0.1, std=0.01)
    

7) Identity / 特殊初始化(主要用于残差或 RNN)

  • Identity: 将权重初始化为单位矩阵(仅方阵层)。常用于某些 RNN 或残差模块以便初期不改变输入。
  • 用途: 保持初始近似恒等映射,有助训练非常深的残差网络(有时作为 shortcut)。
  • PyTorch:
    nn.init.eye_(layer.weight)
    

🧾 偏置(Bias)初始化建议

  • 常用做法: 全部设为 000 (nn.init.zeros_(bias))。
  • ReLU: 有时设小正值(如 0.010.010.01)对 ReLU 有利(防止死神经元)。
  • BatchNorm: 对 BatchNorm 的偏置通常设置 000
  • LSTM/GRU: 可以把 forget gate bias 初始化为正值(如 1.01.01.0)来鼓励初期记忆保持(实践中常用)。

🔧 实务:PyTorch 中典型代码模板

这是一个用于遍历模块并初始化权重的示例函数:

import torch.nn as nn

def init_weights(m):
    # 线性层
    if isinstance(m, nn.Linear):
        # 使用 Kaiming Uniform(或 xavier_uniform_ 配合 tanh/sigmoid)
        nn.init.kaiming_uniform_(m.weight, nonlinearity='relu')
        if m.bias is not None:
            nn.init.zeros_(m.bias)
    # 卷积层
    elif isinstance(m, nn.Conv2d):
        nn.init.kaiming_normal_(m.weight, nonlinearity='relu')
        if m.bias is not None:
            nn.init.zeros_(m.bias)
    # LSTM 单元
    elif isinstance(m, nn.LSTM):
        for name, param in m.named_parameters():
            if 'weight_ih' in name:
                # input-to-hidden 权重用 Xavier
                nn.init.xavier_uniform_(param)
            elif 'weight_hh' in name:
                # hidden-to-hidden 权重用 Orthogonal
                nn.init.orthogonal_(param)
            elif 'bias' in name:
                # 偏置设为 0
                nn.init.zeros_(param)
                # 可选:对遗忘门(forget gate)的偏置做特殊处理,通常设为正值如 1.0 或更高
                # PyTorch LSTM bias 通常是 4*hidden_size 拼接,其中第二个是遗忘门偏置
                # Example for setting forget gate bias to 1.0 (requires careful indexing)
                # param.data.chunk(4)[1].fill_(1.0)

你需要将此函数应用到你的模型:model.apply(init_weights)


📌 选用建议速查表(快速决策)

场景 推荐初始化方法
CNN + ReLU He / Kaiming 初始化(默认首选)
浅网络 / tanh / sigmoid Xavier / Glorot 初始化
SELU LeCun 初始化 + SELU 激活
RNN / LSTM weight_ih 用 Xavier,weight_hh 用 Orthogonal;forget gate bias ≈1\approx 11
大模型 / Transformer 通常使用 Xavier 或 Kaiming;embedding 用正态小方差

⚠️ 常见坑与实践小贴士

  • 激活函数先选再选初始化: ReLU 用 He,tanh⁡\tanhtanh 用 Xavier。
  • BatchNorm 影响: BatchNorm 的存在会缓解初始化敏感性,但仍然需要合理初始化。
  • 可复现性: 初始化受随机种子影响,要复现结果请设置 torch.manual_seed(seed) 且固定 cudnn 后端相关设置。
  • 预训练模型: 若使用预训练权重,通常不再初始化(或只初始化新加层)。
  • Weight decay: L2正则与初始化无直接冲突,但注意不要把 bias decay 也加上(一般不做)。

📎 总结(一句话)

初始化的目标是破对称 + 稳定方差传播,选择应基于激活函数网络结构:ReLU →\to Kaiming,tanh⁡\tanhtanh/sigmoid\text{sigmoid}sigmoid →\to Xavier,SELU →\to LeCun;RNN/复杂结构可用正交或分门别类初始化并对 forget biasforget\ biasforget bias 做特殊处理。

请添加图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐