4. 模型架构选择与初始化:经典模型选型原则、权重初始化方法、预训练模型加载与微调策略
模型选型和初始化,说白了就是给训练打地基。地基没打好,后面再怎么调参也是白费力气。我见过太多同学一上来就上大模型,结果训练半天 loss 纹丝不动,最后发现是初始化出了问题。今天咱们就把这块掰开揉碎了讲清楚。
4.1 经典模型选型原则
选模型不是越新越好,也不是越大越好。你得看你的数据长什么样,任务是什么类型。我个人习惯先问自己三个问题:数据是序列还是网格?任务需要全局理解还是局部特征?算力够不够?
4.1.1 CNN:图像与局部特征的王者
CNN 的核心假设是局部相关性和平移不变性。你想想看,一张猫的图片,不管猫在左边还是右边,卷积核都能认出它的耳朵。这就是 CNN 最擅长的事。
| 适用场景 | 典型模型 | 核心优势 |
|---|---|---|
| 图像分类、目标检测 | ResNet、EfficientNet | 参数共享,计算高效 |
| 语义分割、风格迁移 | U-Net、DeepLab | 空间信息保留好 |
| 视频分析、动作识别 | 3D CNN、I3D | 时空特征联合提取 |
4.1.2 RNN/LSTM:序列建模的老牌选手
RNN 适合处理变长序列,比如文本、语音、时间序列。但说实话,纯 RNN 现在用得少了,梯度消失太严重。LSTM 和 GRU 加了门控机制,能记住长距离依赖。
- LSTM:三个门(遗忘、输入、输出),适合长序列,比如机器翻译、语音识别
- GRU:两个门(重置、更新),参数更少,训练更快,效果和 LSTM 差不多
- 双向 RNN:同时看前后文,适合命名实体识别、情感分析
4.1.3 Transformer:当前的主流选择
Transformer 用自注意力机制替代了循环结构,彻底解决了并行问题。它的核心优势是能捕捉任意距离的依赖关系。嗯,这里要注意,Transformer 不是万能药——它对数据量和算力的要求都不低。
| 模型 | 参数量 | 推荐场景 | 训练成本 |
|---|---|---|---|
| BERT-base | 110M | 文本分类、问答 | 中等 |
| 1.5B | 文本生成 | 高 | |
| ViT | 86M-632M | 图像分类 | 高 |
| Whisper | ~1.5B | 语音识别 | 极高 |
4.2 权重初始化方法
初始化决定了模型从哪个起点开始梯度下降。起点选不好,要么梯度爆炸,要么梯度消失,要么收敛到局部最优。我刚开始做训练时,有一次用全零初始化训一个 10 层网络,训了 3 天 loss 纹丝不动——后来才发现所有神经元输出都一样,梯度根本传不下去。
4.2.1 Xavier 初始化(Glorot 初始化)
Xavier 的核心思想是让每一层的输入和输出方差保持一致。它假设激活函数是线性的(或者接近线性,比如 tanh)。
# PyTorch 实现
import torch.nn as nn
# 对线性层使用 Xavier 初始化
def init_weights(m):
if isinstance(m, nn.Linear):
nn.init.xavier_uniform_(m.weight)
nn.init.zeros_(m.bias)
model = nn.Sequential(
nn.Linear(784, 256),
nn.Tanh(),
nn.Linear(256, 128),
nn.Tanh(),
nn.Linear(128, 10)
)
model.apply(init_weights)
Xavier 适合 tanh、sigmoid 这类饱和激活函数。但如果你用 ReLU,Xavier 就不太行了——ReLU 会把一半的神经元置零,方差会减半。
4.2.2 He 初始化(Kaiming 初始化)
He 初始化专门为 ReLU 设计。它考虑了 ReLU 的稀疏性,把方差放大了一倍。说白了,就是补偿 ReLU 砍掉的那一半信息。
# 对卷积层使用 He 初始化
def init_weights_he(m):
if isinstance(m, nn.Conv2d):
nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
if m.bias is not None:
nn.init.zeros_(m.bias)
# 或者直接用 PyTorch 的默认初始化
# Conv2d 默认就是 kaiming_uniform_
model = nn.Sequential(
nn.Conv2d(3, 64, 3, padding=1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.Conv2d(64, 128, 3, padding=1),
nn.BatchNorm2d(128),
nn.ReLU()
)
| 初始化方法 | 适用激活函数 | 分布类型 | 方差公式 |
|---|---|---|---|
| Xavier Uniform | tanh, sigmoid | 均匀分布 | Var = 2 / (fan_in + fan_out) |
| Xavier Normal | tanh, sigmoid | 正态分布 | Var = 2 / (fan_in + fan_out) |
| He Uniform | ReLU, Leaky ReLU | 均匀分布 | Var = 2 / fan_in |
| He Normal | ReLU, Leaky ReLU | 正态分布 | Var = 2 / fan_in |
4.3 预训练模型加载与微调策略
预训练模型是深度学习最大的「作弊器」。你想想看,别人用几千张 GPU 训了好几个月的模型,你花 5 分钟下载下来,稍微调一调就能用。但怎么用、怎么调,这里头门道不少。
4.3.1 加载预训练模型
PyTorch 加载预训练模型非常方便,但要注意几个坑:
import torchvision.models as models
# 加载预训练 ResNet18
model = models.resnet18(pretrained=True)
# 修改最后一层(假设是 10 分类任务)
num_ftrs = model.fc.in_features
model.fc = nn.Linear(num_ftrs, 10)
# 加载到设备
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = model.to(device)
4.3.2 微调策略:全量微调 vs 冻结微调
微调不是无脑全量训练。你得根据数据量和数据相似度来决定策略。
| 数据量 | 数据相似度 | 推荐策略 | 学习率 |
|---|---|---|---|
| 小(<1万) | 高 | 只训练分类头,冻结主干 | 1e-3 ~ 1e-4 |
| 小(<1万) | 低 | 冻结前几层,微调后几层 | 1e-4 ~ 5e-5 |
| 中(1万~10万) | 高 | 全量微调,但用较小学习率 | 1e-4 ~ 1e-5 |
| 大(>10万) | 低 | 全量微调,从头训部分层 | 1e-4 ~ 1e-5 |
# 冻结主干,只训练分类头
for param in model.parameters():
param.requires_grad = False
# 解冻最后一层
for param in model.fc.parameters():
param.requires_grad = True
# 或者用差分学习率
optimizer = torch.optim.Adam([
{'params': model.fc.parameters(), 'lr': 1e-3},
{'params': model.layer4.parameters(), 'lr': 1e-4},
{'params': model.layer3.parameters(), 'lr': 5e-5},
])
4.4 本章知识体系
下面这张图把模型选型、初始化、微调串起来了。你可以把它当作决策流程图来用。
这张图从左到右展示了完整的决策路径。你拿到一个任务,先看数据类型,再选模型架构,然后确定初始化方法,最后决定微调策略。每一步都有对应的最佳实践。
- CNN 适合图像,RNN 适合短序列,Transformer 是通用方案
- ReLU 用 He 初始化,tanh/sigmoid 用 Xavier 初始化
- 预训练模型是利器,但要注意输入尺寸和归一化参数
- 微调学习率要比从头训练小 10~100 倍
- 数据量少就冻结主干,数据量多就全量微调