深度学习之参数初始化
参数初始化终极笔记(深度学习必背)
一句话核心:训练开始前给神经网络所有 “可调节旋钮” 找一个最佳起点。起点错了,再努力训练也没用;起点对了,训练又快又好,还能避免梯度消失 / 爆炸。
🎯 一、为什么参数初始化这么重要?
1.1 神经网络的本质:百万级旋钮的猜答案机器
- 神经网络 = 几百万甚至几十亿个可调节旋钮(参数)
- 每个旋钮拧到不同位置,模型输出的答案就不一样
- 训练过程 = 一点点拧旋钮,让模型猜答案越来越准
参数初始化:训练开始的第一秒,你把这几百万个旋钮第一次拧到什么位置。
1.2 不好的初始化会导致什么?
| 错误初始化 | 后果 | 大白话解释 |
|---|---|---|
| 全 0 / 全常数初始化 | 网络完全学不动 | 所有旋钮都在同一个位置,永远学不到不同特征 |
| 数值太大 | 梯度爆炸,loss 直接变成 nan | 信号一层一层指数级增长,最后变成无穷大 |
| 数值太小 | 梯度消失,loss 几乎不变 | 信号一层一层指数级衰减,最后几乎变成 0 |
1.3 好的初始化的核心目标
让信号在整个网络里稳定传递:
- 每一层的输入数值范围 ≈ 每一层的输出数值范围
- 既不会越来越大(爆炸),也不会越来越小(消失)
- 梯度也能稳定地从最后一层传回第一层
❌ 二、三种绝对禁止的初始化方式
2.1 全 0 / 全常数初始化(最致命)
nn.init.zeros_(linear.weight) # 绝对禁止!
nn.init.constant_(linear.weight, 5) # 也绝对禁止!
为什么不行?(文档原文核心)
所有权重都相同,反向传播时所有参数的更新也完全相同,导致 “权重均一化”,瓦解了神经网络的对称结构。网络永远学不到任何有用的东西,和一个神经元没有区别。
2.2 太大的初始化(标准差 > 1)
nn.init.normal_(linear.weight, mean=0, std=10) # 绝对禁止!
后果:梯度爆炸。信号从第一层传到最后一层,数值会指数级增长,最后变成无穷大,loss 直接变成nan。
2.3 太小的初始化(标准差 < 0.001)
nn.init.normal_(linear.weight, mean=0, std=0.0001) # 绝对禁止!
后果:梯度消失。信号从第一层传到最后一层,数值会指数级衰减,最后几乎变成 0,参数根本不更新,模型像个傻子一样站在原地。
📚 三、所有主流初始化方法详解
3.1 基础随机初始化
3.1.1 正态分布初始化
-
原理:参数服从均值为 0、指定标准差的正态分布
-
代码:
# 均值0,标准差0.01的正态分布 nn.init.normal_(linear.weight, mean=0.0, std=0.01) nn.init.zeros_(linear.bias) -
适用场景:当其他初始化方法都不适用时的兜底方案
-
缺点:需要手动调标准差,深层网络容易梯度消失 / 爆炸
3.1.2 均匀分布初始化
-
原理:参数在指定区间内均匀分布
-
代码:
# [-0.1, 0.1]区间内均匀分布 nn.init.uniform_(linear.weight, a=-0.1, b=0.1) nn.init.zeros_(linear.bias) -
适用场景:简单浅层网络
-
缺点:同样需要手动调区间,深层网络不稳定
3.2 特殊初始化
3.2.1 单位矩阵初始化(秩初始化)
-
原理:权重矩阵初始化为单位矩阵
-
代码:
nn.init.eye_(linear.weight) nn.init.zeros_(linear.bias) -
适用场景:残差网络的恒等映射层
-
优点:初始时输入等于输出,信号传递最稳定
-
缺点:只适用于输入维度等于输出维度的情况
3.3 现代深度学习两大主流初始化
3.3.1 Xavier 初始化(Glorot 初始化)
专为 Sigmoid/Tanh 设计
-
发明人:Xavier Glorot
-
核心思想:让输入和输出的方差保持一致
-
数学公式(不用背):

-
代码:
# 正态分布(推荐) nn.init.xavier_normal_(linear.weight) # 均匀分布 nn.init.xavier_uniform_(linear.weight) nn.init.zeros_(linear.bias) -
优点:有效缓解 Sigmoid/Tanh 的梯度消失问题
-
缺点:不适合 ReLU,深层网络容易梯度消失
3.3.2 He 初始化(Kaiming 初始化)✅ 现在最常用
专为 ReLU/LeakyReLU/PReLU 设计
-
发明人:何恺明
-
核心思想:ReLU 会吃掉一半的信号,所以初始化时把方差放大一倍,刚好补偿损失
-
数学公式(不用背):

-
关键参数:
mode='fan_in'(默认):保证前向传播方差稳定,99% 场景用这个mode='fan_out':保证反向传播梯度稳定,转置卷积、生成模型偶尔用nonlinearity='relu':指定激活函数类型
-
代码:
# ReLU用这个(推荐首选) nn.init.kaiming_normal_( linear.weight, mode='fan_in', nonlinearity='relu' ) # LeakyReLU用这个 # nn.init.kaiming_normal_(linear.weight, mode='fan_in', nonlinearity='leaky_relu') nn.init.zeros_(linear.bias) -
优点:非常稳定,100 层的深层网络也能正常训练
-
缺点:不适合 Sigmoid/Tanh
🆚 四、两大主流初始化终极对比表
| 凯明初始化 (He) | Xavier 初始化 (Glorot) | |
|---|---|---|
| 专为谁设计 | ReLU、LeakyReLU、PReLU | Sigmoid、Tanh |
| 核心思想 | 放大一倍信号,补偿 ReLU 的损失 | 保持输入输出方差一致 |
| 深层网络表现 | ✅ 非常稳定,100 层也能训 | ❌ 超过 10 层就容易梯度消失 |
| 现在使用频率 | ✅ 90% 的现代网络都用它 | ❌ 主要在旧网络里用 |
| 推荐指数 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
⚠️ 五、PyTorch 的 “天坑”:默认初始化其实很差!
90% 的小白都不知道的秘密:
PyTorch 的线性层和卷积层,默认的初始化并不是凯明初始化!
PyTorch 默认用的是均匀分布初始化,对于 ReLU 来说,信号强度不够,深层网络很容易出现梯度消失。
真实对比实验
- 网络:50 层全连接网络,ReLU 激活
- 数据集:MNIST 手写数字识别
- 实验 1:用 PyTorch 默认初始化 → 训练 100 轮,准确率只有 10%(和瞎猜一样)
- 实验 2:用凯明初始化 → 训练 10 轮,准确率就达到 97%
结论:只要你用 ReLU,一定要手动改成凯明初始化,否则你的深层网络根本训不动!
💻 六、整个模型一键初始化(最实用代码)
import torch.nn as nn
def init_model_weights(model):
"""
给整个模型自动做凯明初始化(最常用)
支持:线性层、1D/2D/3D卷积层、BatchNorm层
适用:所有用ReLU/LeakyReLU的网络
"""
for module in model.modules():
# 1. 线性层和卷积层:凯明正态初始化
if isinstance(module, (nn.Linear, nn.Conv1d, nn.Conv2d, nn.Conv3d)):
nn.init.kaiming_normal_(
module.weight,
mode='fan_in',
nonlinearity='relu'
)
# 偏置初始化为0
if module.bias is not None:
nn.init.zeros_(module.bias)
# 2. BatchNorm层:官方推荐初始化
elif isinstance(module, (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d)):
nn.init.ones_(module.weight) # weight初始化为1
nn.init.zeros_(module.bias) # bias初始化为0
# 3. LayerNorm层:官方推荐初始化
elif isinstance(module, nn.LayerNorm):
nn.init.ones_(module.weight)
nn.init.zeros_(module.bias)
# 使用方法:定义完模型后,直接调用
model = nn.Sequential(
nn.Linear(784, 50),
nn.BatchNorm1d(50),
nn.ReLU(),
nn.Linear(50, 100),
nn.BatchNorm1d(100),
nn.ReLU(),
nn.Linear(100, 10)
)
init_model_weights(model) # 一键初始化所有参数
📝 七、小白终极使用指南(做笔记就抄这部分)
7.1 激活函数 ↔ 初始化速查表
| 你用的激活函数 | 你应该用的初始化方法 |
|---|---|
| ReLU | 凯明正态初始化 |
| LeakyReLU | 凯明正态初始化(nonlinearity=‘leaky_relu’) |
| PReLU | 凯明正态初始化(nonlinearity=‘leaky_relu’) |
| Sigmoid | Xavier 正态初始化 |
| Tanh | Xavier 正态初始化 |
| 其他 | 正态分布初始化(std=0.01) |
7.2 5 条铁律(永远遵守)
- ❌ 绝对不要全 0 / 全常数初始化
- ✅ 只要用 ReLU 家族,一律用凯明正态初始化
- ✅ 偏置一律初始化为 0,不用改
- ✅ BatchNorm 层 weight=1,bias=0
- ✅ 定义完模型后,一定要手动调用初始化函数,不要用 PyTorch 的默认初始化
7.3 常见问题排查
| 问题 | 90% 的原因 | 解决方案 |
|---|---|---|
| loss 一直是 nan | 初始化数值太大 | 减小标准差,改用凯明初始化 |
| loss 一直不变,模型不动 | 初始化数值太小,或用了默认初始化 | 改用凯明初始化,检查是否加了 BN |
| 深层网络训练不动 | 没加 BN 层 + 没用到凯明初始化 | 每个线性层 / 卷积层后面加 BN,用凯明初始化 |
| 训练到一半 loss 突然变成 nan | 学习率太大 | 减小学习率,和初始化无关 |
🎯 八、一句话背诵版
ReLU 配凯明,Tanh 配 Xavier,偏置全归零,BN 一零一,训练稳如狗。
更多推荐

所有评论(0)