欢迎光临
我们一直在努力

13_参数的初始化[pytorch框架与神经网络基础]

参数的初始化

在神经网络中,参数初始化(Parameter Initialization)指的是在训练开始之前设置网络权重(weights)和偏置(biases)的初始值。合适的初始化策略对于神经网络的训练过程至关重要。好的初始化方法能够加速收敛,提高模型的性能,避免一些常见的问题,如梯度消失或梯度爆炸。

参数初始化的作用

  • 加速收敛:
    • 一个好的初始化策略能帮助模型更快地收敛。合适的初始化会避免在训练初期陷入困境,使得梯度在反向传播时不会因为初始值太小或太大而导致学习困难。
  • 避免梯度消失和梯度爆炸:
    • 如果初始化过小或过大,可能导致梯度在反向传播时变得非常小(梯度消失)或非常大(梯度爆炸),从而影响训练的稳定性。
    • 例如,深度网络中的梯度消失问题会导致模型训练速度极慢,甚至无法更新参数;而梯度爆炸则可能导致训练过程中权重更新过快,导致权重的值极大,进而造成不稳定的训练。
  • 确保每个神经元有不同的学习路径:
    • 如果所有神经元的初始权重相同,那么每个神经元将执行相同的操作,导致它们在训练过程中学习到相同的特征,这会大大降低模型的表现。
    • 通过合理的初始化方法,确保每个神经元从不同的初始值开始学习,使得它们能学习到不同的特征,提高模型的多样性和表现。
  • 避免对称性破坏:
    • 如果所有权重被初始化为相同的值,所有神经元的输出也将相同,导致网络在训练过程中无法破除对称性,使得每个神经元的更新是一样的,无法发挥出网络的深度特性。合理初始化权重能够避免这一问题。
  • 初始化方式

    1. 常数初始化

    将参数初始化为固定的常数或简单的矩阵结构的方式。

  • 全0/全1初始化
    • 将神经网络中的所有权重参数初始化为 0/1
  • 固定值初始化
    • 将神经网络中的所有权重参数初始化为某个固定值
  • 单位阵初始化
    • 把d维单位矩阵填充进二维张量中,其中d是这个二维张量维度的最小值即d = argmin(tensor.shape)
  • 狄拉克初始化
    • 把一个 3/4/5 维卷积核张量初始化成 Dirac delta 函数(狄拉克δ函数),使得卷积层在初始时尽可能保持输入恒等(identity)。
  • 2. 简单随机初始化

    从基本的概率分布中采样。

    2.1 均匀分布初始化
    • 从均匀分布

      U

      (

      a

      ,

      b

      )

      U(a, b)

      U(a,b) 中采样,默认

      U

      (

      0

      ,

      1

      )

      U(0,1)

      U(0,1)

    2.2 正态分布初始化
    • 从正态分布

      N

      (

      mean

      ,

      std

      )

      \\mathcal{N}(\\text{mean}, \\text{std})

      N(mean,std) 中采样

    2.3 截断正态分布初始化
    • 从截断的

      N

      (

      mean

      ,

      std

      )

      \\mathcal{N}(\\text{mean}, \\text{std})

      N(mean,std) 中采样,截断区间为

      (

      a

      ,

      b

      )

      (a,b)

      (a,b),可以有效避免极端值

    • 截断正态分布把采样范围限制在

      [

      a

      ,

      b

      ]

      [a, b]

      [a,b] 内,并重新归一化概率密度,使其积分仍为 1:

      f

      (

      x

      μ

      ,

      σ

      ,

      a

      ,

      b

      )

      =

      ϕ
       ⁣

      (

      x

      μ

      σ

      )

      σ

      [

      Φ
       ⁣

      (

      b

      μ

      σ

      )

      Φ
       ⁣

      (

      a

      μ

      σ

      )

      ]

      ,

      a

      x

      b

      f(x \\mid \\mu, \\sigma, a, b) = \\frac{\\phi\\!\\left(\\frac{x-\\mu}{\\sigma}\\right)}{\\sigma\\left[\\Phi\\!\\left(\\frac{b-\\mu}{\\sigma}\\right) – \\Phi\\!\\left(\\frac{a-\\mu}{\\sigma}\\right)\\right]}, \\quad a \\le x \\le b

      f(xμ,σ,a,b)=σ[Φ(σbμ)Φ(σaμ)]ϕ(σxμ),axb

    • 作用

    • 避免极端值: 正态分布理论上无界。在深层网络中,偶尔出现的

      4

      σ

      4\\sigma

      4σ

      5

      σ

      5\\sigma

      5σ 权重可能导致:

      • 激活值爆炸;
      • 梯度消失/爆炸;
      • 训练早期 loss 出现 NaN。
    • 比均匀分布更"合理"的先验: 很多场景下,我们相信权重应该集中在 0 附近(小权重优先),而不是均匀地散在整个区间。均匀分布给

      [

      r

      ,

      r

      ]

      [-r, r]

      [r,r] 内每个值同等概率,这在先验上未必合理。截断正态以 0 为中心、钟形衰减,更符合"权重应小且集中"的直觉。

    3. 自适应初始化(基于网络结构所提出的特定初始化方式)

    3.1 kaiming 初始化

    He 初始化是专为 ReLU 类激活函数设计的权重初始化方法,由何恺明等人于 2015 年在论文《Delving Deep into Rectifiers》中提出。 核心思想是:根据每层的 fan 数自动计算初始化尺度,让信号在多层前向/反向传播中保持方差稳定。

    计算方式:

  • 计算标准差

    std

    =

    gain

    fan_mode

    \\text{std} = \\frac{\\text{gain}}{\\sqrt{\\text{fan\\_mode}}}

    std=fan_mode

    gain 其中:

    • gain:激活函数增益,如激活函数为ReLU 时

      gain

      =

      2

      \\text{gain} = \\sqrt{2}

      gain=2

    • fan_mode:fan_in(输入维度,默认)或 fan_out(输出维度)
  • 采样
    • 正态分布的He初始化: 从

      N

      (

      0

      ,

      std

      2

      )

      \\mathcal{N}(0, \\text{std}^2)

      N(0,std2)采样

    • 均匀分布的He初始化: 从

      U

      (

      3

      std)

      ,

      3

      std)

      )

      \\mathcal{U}(-\\sqrt{3}\\text{std)},\\sqrt{3}\\text{std)})

      U(3

      std),3

      std))采样

  • 本质上,

    N

    (

    0

    ,

    std

    2

    )

    \\mathcal{N}(0, \\text{std}^2)

    N(0,std2)

    U

    (

    3

    std)

    ,

    3

    std)

    )

    \\mathcal{U}(-\\sqrt{3}\\text{std)},\\sqrt{3}\\text{std)})

    U(3

    std),3

    std))的期望和方差一致。

    两者的区别在于:

  • 正态版本有概率产生极端值而均匀版本不会
  • 正态版本在0附近的密度更高
  • 在量化训练或低精度(FP16/BF16)场景下:
    • normal 版可能出现超出表示范围的值,需要额外裁剪;
    • uniform 版范围已知,更容易做 scale 和量化。
  • 不过貌似大多数论文都用正态的He初始化??可能是为了更方便进行理论分析(CLT之类)??

    3.2 xavier 初始化

    Xavier 初始化是专为 Sigmoid / Tanh 等"近似线性"激活函数设计的权重初始化方法,由 Glorot 和 Bengio 于 2010 年在论文《Understanding the difficulty of training deep feedforward neural networks》中提出。 核心目标:让信号在多层前向和反向传播中保持方差稳定,避免梯度消失或爆炸。 xavier 初始化同样有两个版本:

  • 均匀分布的Xavier初始化

    w

    U

    (

    a

    ,

    a

    )

    ,

    a

    =

    gain

    ×

    6

    fan_in

    +

    fan_out

    w \\sim \\mathcal{U}(-a, a), \\quad a = \\text{gain} \\times \\sqrt{\\frac{6}{\\text{fan\\_in} + \\text{fan\\_out}}}

    wU(a,a),a=gain×fan_in+fan_out6

  • 正态分布的Xavier初始化

    w

    N

    (

    0

    ,

    std

    2

    )

    ,

    std

    =

    gain

    ×

    2

    fan_in

    +

    fan_out

    w \\sim \\mathcal{N}(0, \\text{std}^2), \\qquad \\text{std} = \\text{gain} \\times \\sqrt{\\frac{2}{\\text{fan\\_in} + \\text{fan\\_out}}}

    wN(0,std2),std=gain×fan_in+fan_out2

    其中,fan_in 是输入神经元的个数, fan_out 是输出的神经元个数,gain 是一个可选缩放因子,默认 1.0,用于适配不同激活函数

  • 原理

    Xavier初始化试图使得每一层的输出的方差接近于其输入的方差。简单来说,在不考虑激活函数和偏置项的情况下: 假设

    x

    =

    {

    x

    j

    }

    ,

    (

    j

    =

    1

    ,

    2

    ,


    ,

    fan_in

    )

    x = \\{x_j \\}, (j = 1,2,\\cdots,\\text{fan\\_in})

    x={xj},(j=1,2,,fan_in),

    y

    =

    {

    y

    i

    }

    =

    {

    j

    fan_in

    x

    j

    w

    i

    j

    }

    ,

    (

    i

    =

    1

    ,

    2

    ,


    ,

    fan_out

    )

    \\displaystyle y=\\{y_i\\} = \\{ \\sum_{j}^{\\text{fan\\_in}} x_j * w_{ij} \\} ,(i = 1,2,\\cdots,\\text{fan\\_out})

    y={yi}={jfan_inxjwij},(i=1,2,,fan_out) 且计算过程中的随机变量都服从零均值的独立同分布假设。于是:

    D

    (

    y

    i

    )

    =

    D

    (

    j

    =

    1

    fan_in

    w

    i

    j

    x

    j

    )

    =

    E

    [

    (

    j

    =

    1

    fan_in

    w

    i

    j

    x

    j

    )

    2

    ]

    =

    j

    =

    1

    fan_in

    E

    [

    w

    i

    j

    2

    ]

    E

    [

    x

    j

    2

    ]

    =

    fan_in

    D

    (

    w

    )

    D

    (

    x

    )

    D

    (

    L

    x

    j

    )

    =

    D

    (

    i

    =

    1

    fan_out

    L

    y

    i

    y

    i

    x

    j

    )

    =

    D

    (

    i

    =

    1

    fan_out

    L

    y

    i

    w

    i

    j

    )

    =

    E

    (

    [

    i

    =

    1

    fan_out

    L

    y

    i

    w

    i

    j

    ]

    2

    )

    =

    i

    =

    1

    fan_out

    E

    [

    (

    L

    y

    i

    )

    2

    ]

    E

    [

    w

    i

    j

    2

    ]

    =

    fan_out 

    D

    (

    w

    )

    D

    (

    L

    y

    i

    )

    \\begin{align} &D(y_i) = D(\\sum_{j=1}^{\\text{fan\\_in}}{w_{ij}x_j}) = E[(\\sum_{j=1}^{\\text{fan\\_in}}{w_{ij}x_j})^2] = \\sum_{j=1}^{\\text{fan\\_in}} E[w_{ij}^2]E[x_j^2] = \\text{fan\\_in} * D(w) * D(x) \\\\ &D(\\frac{\\partial{L}}{\\partial{x_j}}) = D(\\sum_{i=1}^{\\text{fan\\_out}} \\frac{\\partial{L}}{\\partial{y_i}} \\cdot \\frac{\\partial{y_i}}{\\partial{x_j}}) \\\\ &= D(\\sum_{i=1}^{\\text{fan\\_out}} \\frac{\\partial{L}}{\\partial{y_i}} \\cdot w_{ij}) \\\\ &= E([\\sum_{i=1}^{\\text{fan\\_out}} \\frac{\\partial{L}}{\\partial{y_i}} \\cdot w_{ij}]^2) \\\\ &= \\sum_{i=1}^{\\text{fan\\_out}} E[(\\frac{\\partial{L}}{\\partial{y_i}})^2] \\cdot E[w_{ij}^2] = \\text{fan\\_out } * D(w) * D(\\frac{\\partial{L}}{\\partial{y_i}}) \\end{align}

    D(yi)=D(j=1fan_inwijxj)=E[(j=1fan_inwijxj)2]=j=1fan_inE[wij2]E[xj2]=fan_inD(w)D(x)D(xjL)=D(i=1fan_outyiLxjyi)=D(i=1fan_outyiLwij)=E([i=1fan_outyiLwij]2)=i=1fan_outE[(yiL)2]E[wij2]=fan_out D(w)D(yiL) 为了同时兼顾前向传播和反向传播时两边的方差,于是取其调和平均数

    D

    (

    w

    )

    =

    2

    fan_in + fan_out

    D(w) = \\frac{2}{\\text{fan\\_in + fan\\_out}}

    D(w)=fan_in + fan_out2

    a

    =

    6

    fan_in + fan_out

    a = \\sqrt{\\frac{6}{\\text{fan\\_in + fan\\_out}}}

    a=fan_in + fan_out6

    时,

    D

    (

    X

    )

    =

    (

    2

    l

    i

    m

    i

    t

    )

    2

    12

    =

    2

    fan_in + fan_out

    D(X) = \\frac{(2 * limit)^2}{12} = \\frac{2}{\\text{fan\\_in + fan\\_out}}

    D(X)=12(2limit)2=fan_in + fan_out2

    3.3 正交初始化
    • 将矩阵初始化为(半)正交矩阵,常用于 RNN 中缓解梯度消失/爆炸。
    3.4 稀疏初始化
    • 将二维张量初始化为稀疏矩阵,非零元素来自正态分布。

    4. 增益率

    如果知道了具体的激活函数,你可以通过计算它的增益来调整方差

    D

    (

    w

    )

    D(w)

    D(w)。或者你可以在pytorch中查找对应函数的增益率。计算方式如下

    g

    a

    i

    n

    =

    D

    (

    x

    )

    D

    [

    f

    (

    x

    )

    ]

    f

    (

    x

    )

    为对应的激活函数

    gain = \\sqrt{\\frac{D(x)}{D[f(x)]}} \\quad f(x)\\text{为对应的激活函数}

    gain=D[f(x)]D(x)

    f(x)为对应的激活函数 不过计算积分比较复杂,所以推荐查表或使用蒙特卡洛法计算:

    import torch
    import math

    def estimate_gain(activation_func, num_samples=1000000):
    x = torch.randn(num_samples) # 标准正态分布
    y = activation_func(x)
    var_x = x.var().item()
    var_y = y.var().item()
    return math.sqrt(var_x / var_y)

    # 估计SiLU的增益
    gain_silu = estimate_gain(lambda x: x * torch.sigmoid(x))
    print(gain_silu)

    ## tanh的增益率
    print(torch.nn.init.calculate_gain('tanh'))

    使用:

    • torch.nn.init.normal_(weight, mean=0.0, std=math.sqrt(2.0/(fan_in+0.0))*gain)
    • torch.nn.init.xavier_normal_(weight,gain=gain)
    • torch.nn.init.kaiming_normal_(weight,nonlinearity='relu')

    ================= ====================================================
    nonlinearity gain
    ================= ====================================================
    Linear / Identity :math:`1`
    Conv{1,2,3}D :math:`1`
    Sigmoid :math:`1`
    Tanh :math:`\\frac{5}{3}`
    ReLU :math:`\\sqrt{2}`
    Leaky Relu :math:`\\sqrt{\\frac{2}{1 + \\text{negative\\_slope}^2}}`
    SELU :math:`\\frac{3}{4}`
    ================= ====================================================


    参考

    • pytorch官方文档
    • 动手深度学习
    赞(0)
    未经允许不得转载:171主机测评 » 13_参数的初始化[pytorch框架与神经网络基础]
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址