深度学习×第7卷:参数初始化与网络搭建——她第一次挑好初始的重量
🎀【开场 · 她学会选一块好吃的起点】
🐾猫猫:“之前她有了张量、有了弯弯,还学会了怎么连成一张网……可要是随便塞点数字进去,她跑着跑着就会贴得乱七八糟喵~”
🦊狐狐:“所以这一次,她要学会选一块对的‘初始重量’,让每条线都带着合适的力气起跑。”
这一卷,咱要讲清楚:参数初始化(Initialization) 为什么是让她跑得好跑得远的第一口饭,从最简单的全零、均匀、正态,到 Xavier 和 Kaiming,每种都要举例、要有 PyTorch 代码,还要告诉她跟谁搭配才最合适。
🌱【第一节 · 为什么要初始化?】
🔍 如果不初始化会怎样?
如果把神经网络的权重都设成 0,会怎样?
🐾猫猫:“她所有神经元就像用一模一样的笔写字,谁都学不到自己的特色喵~”
如果权重太大或太小,层数一多,前向传播时值会爆炸或收缩到 0,导致梯度在反向传播时要么炸掉要么消失。
🦊狐狐:“她要是随便挑个重量就开跑,很快就要么把梯度丢光,要么一路爆炸跑没影。”
📌 初始化的目标
打破对称性(每个神经元学自己的)
保证激活值分布稳定
保证梯度在前后传播时不消失也不爆炸
🐾猫猫:“所以初始化就是喂她吃第一口对的饭,让她有力气开始贴贴喵~”
🌿【第二节 · 全零、均匀、正态随机初始化】
⚙️ 全零初始化
把权重全设成 0,偏置也设成 0,看起来“整齐”,其实是灾难。所有神经元输出完全相同,网络无法学多样性。
🐾猫猫:“她就像所有脑袋都背同一句台词,谁都学不会新花样喵~”
import torch.nn as nnlayer = nn.Linear(3, 2)
nn.init.constant_(layer.weight, 0.0)
nn.init.constant_(layer.bias, 0.0)
🟢 均匀随机初始化
从一个区间内随机抽数,一般在 [-a, a],保证权重不一样,打破对称。
import torch.nn.init as initlayer = nn.Linear(3, 2)
init.uniform_(layer.weight, a=-0.1, b=0.1)
init.constant_(layer.bias, 0.0)
🟠 正态随机初始化
从均值为 0 的高斯分布里抽样,控制标准差,保证值多数集中但有分散性。
layer = nn.Linear(3, 2)
init.normal_(layer.weight, mean=0.0, std=0.05)
init.constant_(layer.bias, 0.0)
📌 小结
全零:绝对不能用
均匀、正态:最简单的基础做法,但不考虑输入输出规模,可能层数多了就会出事。
🦊狐狐:“真正能跑得远,还得学会 Xavier 和 Kaiming,咱下一节拆给你看。”
🐾猫猫:“别急,这口饭才刚煮好喵~”
🧩【第三节 · Xavier 和 Kaiming:她选重量也讲科学】
⚙️ Kaiming 初始化(He 初始化)
专为 ReLU 及其变体设计,考虑 ReLU 截断后的特性,对输入维度 fan_in 缩放
正态分布 He 初始化:w ~ N(0, sqrt(2 / fan_in))
均匀分布 He 初始化:w ~ U(-limit, limit),limit = sqrt(6 / fan_in)
fan_in:当前层接收的输入神经元数量
优点:适合 ReLU,保持梯度稳定
缺点:非 ReLU 激活效果一般
适用场景:深度网络(10 层以上),ReLU 或 Leaky ReLU 激活
# Kaiming 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_normal_(linear.weight, nonlinearity='relu')
print(linear.weight.data)# Kaiming 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.kaiming_uniform_(linear.weight, nonlinearity='relu')
print(linear.weight.data)
⚙️ Xavier 初始化(Glorot 初始化)
根据 fan_in 和 fan_out 自动选择范围,使输入输出方差一致
正态分布 Xavier 初始化:w ~ N(0, sqrt(2 / (fan_in + fan_out)))
均匀分布 Xavier 初始化:w ~ U(-limit, limit),limit = sqrt(6 / (fan_in + fan_out))
fan_in:当前层输入数;fan_out:当前层输出数
优点:适合 Sigmoid、Tanh,缓解梯度消失
缺点:对 ReLU 效果一般
适用场景:深度网络(10 层以上),Sigmoid、Tanh 激活
# Xavier 正态分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_normal_(linear.weight)
print(linear.weight.data)# Xavier 均匀分布初始化
linear = nn.Linear(5, 3)
nn.init.xavier_uniform_(linear.weight)
print(linear.weight.data)
⚙️激活函数的选择:根据激活函数的类型选择对应的初始化方法
Sigmoid/Tanh:xavier 初始化
ReLU/Leaky ReLU:kaiming 初始化
神经网络模型的深度
浅层网络:随机初始化即可
深层网络:需要考虑方差平衡,如 xavier 或 kaiming 初始化
🐾猫猫:“她挑对了初始重量,跑起来才不会炸掉或者瘪成 0 喵~”
🦊狐狐:“下一节咱就把这套好权重装进自定义网络里,跑个小样子给你看。”
🧩【第四节 · nn.Module 搭建 + 参数量计算(完整版 Part 1)】
📐 一、先搭一个多层网络,画出示意图
🐾猫猫:“她这回要从输入层、隐藏层1、隐藏层2、输出层,全部自己连成一张小网喵~”
import torch
import torch.nn as nn
import torch.nn.init as initclass MyMLP(nn.Module):def __init__(self):super(MyMLP, self).__init__()self.fc1 = nn.Linear(4, 5) # 输入4,输出5self.fc2 = nn.Linear(5, 3) # 输入5,输出3self.out = nn.Linear(3, 2) # 输入3,输出2# 权重初始化:kaiming示例init.kaiming_uniform_(self.fc1.weight, nonlinearity='relu')init.kaiming_uniform_(self.fc2.weight, nonlinearity='relu')init.kaiming_uniform_(self.out.weight, nonlinearity='relu')init.constant_(self.fc1.bias, 0)init.constant_(self.fc2.bias, 0)init.constant_(self.out.bias, 0)def forward(self, x):x = torch.relu(self.fc1(x))x = torch.relu(self.fc2(x))x = self.out(x)return xmodel = MyMLP()
print(model)
📌 参数量(手动)
fc1: (4×5) + 5 = 25
fc2: (5×3) + 3 = 18
out: (3×2) + 2 = 8
合计:51 个可学习参数
🐾猫猫:“别小看这 51 个,她可要用这 51 个贴贴你输入的每个特征喵~”
🔄 二、输入张量跑前向,验证输出 shape
# 定义输入张量:batch size = 2,输入特征 4
x = torch.rand(2, 4)# 前向传播
output = model(x)
print("输入 shape:", x.shape)
print("输出 shape:", output.shape)
🐾猫猫:“她吃进两个样本,每个 4 个特征,吐出来两个样本,每个 2 个输出喵~”
✅ 用 torchsummary 也可以更直观
from torchsummary import summary
summary(model, (4,))
🦊狐狐:“summary 一下,层结构、输出形状、参数量,一眼心里有数。”
📌 三、state_dict 和 named_parameters 全面检查
🐾猫猫:“她跑完还要自己翻包裹,看每个权重和偏置是不是都带好了喵~”
print("====== State Dict ======")
for name, param in model.state_dict().items():print(name, param.shape)print("====== Named Parameters ======")
for name, param in model.named_parameters():print(f"{name}: shape={param.shape}, requires_grad={param.requires_grad}")
🦊狐狐:“state_dict 是她带着跑的行囊,named_parameters 是她手里每个可训练的小秘密。”
✅ 额外 sanity check
可选:看某个权重的均值、方差,确认初始化确实生效。
print("fc1 weight 均值:", model.fc1.weight.mean().item())
print("fc1 weight 方差:", model.fc1.weight.var().item())
🐾猫猫:“检查完,她才放心把这些重量拿去真的跑喵~”
📌 四、可视化补充 + torchinfo 用法(可选扩展)
🐾猫猫:“光看打印不够爽,有时候要直接用 torchinfo 给她画个小表喵~”
from torchinfo import summarysummary(model, input_size=(2, 4))
input_size
指定 batch 大小和输入维度会显示层级、输出形状、参数量、可训练状态等信息
📝 核对点
权重 shape 和 fan_in/fan_out 是否一致
总参数量是否对得上手算值
requires_grad = True 保证可训练
🦊狐狐:“有 torchinfo,她连跑的时候都能实时数着自己背了多少贴贴工具。”
🐾猫猫:“这样这一节,才算把‘初始化选好 + 网络拼好 + 参数数好’全都扒给你看完喵~”
📌【卷尾 · 她带着对的重量开始跑】
这卷咱从最简单的 0 初始化,到随机、Xavier、Kaiming,一步步教她怎么挑第一口对的重量。再把多层网拼好,跑前向,数参数,检查 state_dict,验证一切都能贴得稳。
🐾猫猫:“下一卷,她就真的跑起来,去学着一次次修正这些重量喵~”
🦊狐狐:“跑、回头、再跑,这才是她和你之间真正的‘训练’。”