梯度问题与权重初始化
通过与激活匹配的初始化维持前向激活和反向梯度尺度。
学习目标
- 比较 4 个与 100 个输入连接的初始化尺度
- 为什么不能把所有隐藏层权重都设为零?
- 说明:初始化只能改善起点;错误学习率、饱和激活或坏数据仍会破坏梯度传播。
为什么需要这个概念
参数初始化为训练前的权重和偏置选择初值。Xavier、Kaiming 等规则按输入输出连接数和激活特性设定权重方差,以控制前向或反向的量级。
学习前需要掌握
背景与问题
反向梯度需要穿过许多层。如果每层都把信号放大或缩小一点,深层网络就可能很快出现梯度爆炸或消失。初始化关注的是训练起点的信号尺度。
概念定义
参数初始化为训练前的权重和偏置选择初值。Xavier、Kaiming 等规则按输入输出连接数和激活特性设定权重方差,以控制前向或反向的量级。
直观理解
深层网络像许多级放大器串联。每级增益都偏大时会溢出,偏小时信号消失;初始化希望整体先处在可学习的范围。
核心原理
若输入各维近似独立、均值为零且方差相近,线性加权和的方差约为 fan_in×Var(w)×Var(x)。因此连接数越多,单个权重通常应越小;固定所有层都用同一个标准差并不稳妥。
ReLU 会截掉部分信号,Kaiming 的常见 fan_in 规则取权重方差约 2/fan_in。Xavier 同时考虑 fan_in 与 fan_out,常用于近似对称的非线性。它们依赖近似假设,残差、归一化和特殊输出层可能需要不同配方。
若同一层所有隐藏单元权重完全相同,梯度也可能保持对称,多个单元无法分工。随机初始化负责打破这种对称;偏置置零通常没有相同问题。设置种子有利于复核,但不代表跨设备完全一致。
数学表达
核心公式
参数初始化为训练前的权重和偏置选择初值。Xavier、Kaiming 等规则按输入输出连接数和激活特性设定权重方差,以控制前向或反向的量级。
变量含义
fan_in每个输出接收的输入数
计算步骤
- 1计算权重方差 2/fan_in。
- 2标准差分别为 sqrt(0.5) 与 sqrt(0.02)。
代码对应位置
示例 1比较 4 个与 100 个输入连接的初始化尺度的最小验证:使用完整构造输入核对比较 4 个与 100 个输入连接的初始化尺度,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
fan_in | 每个输出接收的输入数 |
完整数值示例
比较 4 个与 100 个输入连接的初始化尺度
已知条件
- 使用 ReLU 的 fan_in 方差规则
- 两层 fan_in 分别为 4 和 100
计算步骤
- 计算权重方差 2/fan_in。
- 标准差分别为 sqrt(0.5) 与 sqrt(0.02)。
计算结果
理论标准差分别约为 0.707107 与 0.141421;输入连接更多时单个权重更小。
处理前后对比
- 初始化只能改善起点;错误学习率、饱和激活或坏数据仍会破坏梯度传播。
案例推演与判断
对 fan_in=100 的层,如果仍使用 0.707 的标准差,线性加权和的方差估计会比目标大很多。这个问题在多层相乘后更明显,不能仅靠训练更久解决。
有限个随机权重的样本标准差不会恰好等于理论值,代码因此打印理论尺度与张量形状,而不把一次随机采样误差当成规则失效。实际排查还应记录激活和梯度的统计量。
计算与实现步骤
- 计算权重方差 2/fan_in。
- 标准差分别为 sqrt(0.5) 与 sqrt(0.02)。
代码实现
示例 1
比较 4 个与 100 个输入连接的初始化尺度的最小验证
example_01.py用途:使用完整构造输入核对比较 4 个与 100 个输入连接的初始化尺度,输出只表示本例计算。
import math
import torch
from torch import nn
torch.manual_seed(7)
for fan_in in [4, 100]:
layer = nn.Linear(fan_in, 8)
nn.init.kaiming_normal_(layer.weight, mode="fan_in", nonlinearity="relu")
nn.init.zeros_(layer.bias)
print(f"fan_in={fan_in} target_std={math.sqrt(2 / fan_in):.6f} shape={tuple(layer.weight.shape)}")代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对比较 4 个与 100 个输入连接的初始化尺度,输出只表示本例计算。
Step 1 · 1–9 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import math
import torch
from torch import nn
torch.manual_seed(7)
for fan_in in [4, 100]:
layer = nn.Linear(fan_in, 8)
nn.init.kaiming_normal_(layer.weight, mode="fan_in", nonlinearity="relu")
nn.init.zeros_(layer.bias)
print(f"fan_in={fan_in} target_std={math.sqrt(2 / fan_in):.6f} shape={tuple(layer.weight.shape)}")代码与数学原理
减去训练均值并除以训练标准差,对应代码中的 mean/std 或 StandardScaler。
预期输出或运行结果
fan_in=4 target_std=0.707107 shape=(8, 4) fan_in=100 target_std=0.141421 shape=(8, 100)
常见错误 · 6 条
- 不要在测试集上调用 fit 或 fit_transform;测试集只能复用训练参数。
- 每 epoch 重置
- 激活不匹配
- 输出层照搬
- 初始化后替换 Parameter
- 确认样本轴、特征轴以及 X 与 y 的第一维完全对应。
实际应用
- 深层 MLP 与 CNN 的训练起点
- 排查层间激活方差异常
常见错误
- 每 epoch 重置
- 激活不匹配
- 输出层照搬
- 初始化后替换 Parameter
常见问题
为什么不能把所有隐藏层权重都设为零?
同层神经元会给出相同输出并接收相同梯度,无法打破对称形成不同特征;随机权重让它们从不同方向开始。
这个示例能说明什么边界?
初始化只能改善起点;错误学习率、饱和激活或坏数据仍会破坏梯度传播。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。