4. 模型架构选择与初始化:经典模型选型原则、权重初始化方法、预训练模型加载与微调策略

模型选型和初始化,说白了就是给训练打地基。地基没打好,后面再怎么调参也是白费力气。我见过太多同学一上来就上大模型,结果训练半天 loss 纹丝不动,最后发现是初始化出了问题。今天咱们就把这块掰开揉碎了讲清楚。

4.1 经典模型选型原则

选模型不是越新越好,也不是越大越好。你得看你的数据长什么样,任务是什么类型。我个人习惯先问自己三个问题:数据是序列还是网格?任务需要全局理解还是局部特征?算力够不够?

4.1.1 CNN:图像与局部特征的王者

CNN 的核心假设是局部相关性和平移不变性。你想想看,一张猫的图片,不管猫在左边还是右边,卷积核都能认出它的耳朵。这就是 CNN 最擅长的事。

适用场景 典型模型 核心优势
图像分类、目标检测 ResNet、EfficientNet 参数共享,计算高效
语义分割、风格迁移 U-Net、DeepLab 空间信息保留好
视频分析、动作识别 3D CNN、I3D 时空特征联合提取
我的经验:如果数据量少于 10 万张,别自己从头训 CNN。用预训练的 ResNet 或 EfficientNet 做迁移学习,效果远好于自己瞎折腾。我曾经有个项目只有 5000 张医疗影像,硬训 VGG 直接过拟合,换成预训练 ResNet 后准确率从 62% 飙到 89%。

4.1.2 RNN/LSTM:序列建模的老牌选手

RNN 适合处理变长序列,比如文本、语音、时间序列。但说实话,纯 RNN 现在用得少了,梯度消失太严重。LSTM 和 GRU 加了门控机制,能记住长距离依赖。

  • LSTM:三个门(遗忘、输入、输出),适合长序列,比如机器翻译、语音识别
  • GRU:两个门(重置、更新),参数更少,训练更快,效果和 LSTM 差不多
  • 双向 RNN:同时看前后文,适合命名实体识别、情感分析
注意:RNN 系列天生不适合并行计算。你想想看,每个时间步都得等前一个算完。如果序列长度超过 100,训练速度会慢到让你怀疑人生。这时候 Transformer 是更好的选择。

4.1.3 Transformer:当前的主流选择

Transformer 用自注意力机制替代了循环结构,彻底解决了并行问题。它的核心优势是能捕捉任意距离的依赖关系。嗯,这里要注意,Transformer 不是万能药——它对数据量和算力的要求都不低。

模型 参数量 推荐场景 训练成本
BERT-base 110M 文本分类、问答 中等
1.5B 文本生成 高
ViT 86M-632M 图像分类 高
Whisper ~1.5B 语音识别 极高
选型口诀:图像用 CNN 或 ViT,文本用 Transformer,序列不长且数据少用 LSTM,算力有限用轻量版(MobileNet、DistilBERT)。

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
实用建议:如果你不确定用哪个,直接用 He 初始化。现在大部分框架(PyTorch、TensorFlow)的默认初始化就是 He。但如果你用 tanh 或 sigmoid,记得手动改成 Xavier。我曾经踩过这个坑——用 He 初始化训 tanh 网络,前几层输出直接饱和,梯度全没了。

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)
常见坑:预训练模型的输入尺寸、归一化参数、类别数可能和你的数据不一样。比如 ImageNet 预训练模型要求输入 224x224,归一化用 mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]。忘了改这些,模型直接废掉。

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},
])
我的经验:微调时学习率要比从头训练小 10~100 倍。预训练模型已经在一个很好的局部最优附近,学习率太大一步就跨出去了。我习惯先用 1e-4 试跑 5 个 epoch,如果 loss 震荡就降到 1e-5。

4.4 本章知识体系

下面这张图把模型选型、初始化、微调串起来了。你可以把它当作决策流程图来用。

模型架构选择与初始化决策流程 输入:任务与数据 图像/网格数据 序列/文本数据 多模态/大模型 CNN / ViT ResNet / EfficientNet RNN / LSTM / Transformer BERT / / T5 CLIP / BLIP / LLaMA ViT + LLM 联合 He 初始化(ReLU) Xavier(tanh/sigmoid) He 或自定义初始化 预训练加载 冻结主干 / 微调后层 学习率 1e-4 ~ 1e-5 预训练加载 全量微调 / 差分学习率 学习率 5e-5 ~ 1e-5 预训练加载 LoRA / Adapter 微调 学习率 1e-4 ~ 1e-5 输出:训练好的模型 提示:数据量少时优先用预训练 + 冻结微调;数据量大时全量微调 + 差分学习率效果更好

这张图从左到右展示了完整的决策路径。你拿到一个任务,先看数据类型,再选模型架构,然后确定初始化方法,最后决定微调策略。每一步都有对应的最佳实践。

核心要点回顾:
  • CNN 适合图像,RNN 适合短序列,Transformer 是通用方案
  • ReLU 用 He 初始化,tanh/sigmoid 用 Xavier 初始化
  • 预训练模型是利器,但要注意输入尺寸和归一化参数
  • 微调学习率要比从头训练小 10~100 倍
  • 数据量少就冻结主干,数据量多就全量微调