@浙大疏锦行
一、预训练核心概念
1.预模型的定义
对比人类学习:
- 预训练 = 九年义务教育(学通用知识:语文、数学、基础科学);
- 你的具体任务 = 大学专业课(比如计算机、医学);
- 直接从头训练 = 跳过九年义务教育,直接学专业课(效率低、学不会)。
在深度学习中,预训练是指:
针对某一类通用任务(如图像特征提取),在大规模通用数据集(如 ImageNet、COCO)上,用大量算力训练一个基础模型(如 ResNet、VGG),让模型学习到该领域的通用特征表示能力;训练完成后,保存模型的权重参数(即 “预训练权重”),后续针对具体任务(如猫狗分类),直接复用这些权重,无需从零开始训练。
核心关键词拆解:
| 关键词 | 解释(CV 场景) |
|---|---|
| 大规模通用数据集 | 不是你的小众任务数据(如几百张猫狗图),而是覆盖范围广的数据集(如 ImageNet 含 1000 类自然图像) |
| 通用特征表示 | 模型学到的不是 “识别猫 / 狗”,而是 “识别边缘、纹理、圆形、方形、物体轮廓” 等所有图像共有的特征 |
| 预训练权重 | 训练完成后保存的模型参数(.pth 文件),是 “通用知识” 的载体 |
| 复用 | 后续任务直接加载这些权重,不用从随机初始化的参数开始训 |
2.预训练的核心逻辑
CNN 的特征提取规律是 “从通用到专属”:
- 底层卷积层:学通用特征(边缘、纹理、颜色)—— 所有图像任务都需要;
- 高层卷积层:学专属特征(物体部件、场景)—— 不同任务有差异。
预训练的本质就是:用海量数据把 “底层通用特征” 学透(这一步需要大量算力和数据,个人 / 小团队做不到),后续任务只需要在这个基础上,微调高层特征适配自己的任务即可。
3.预训练的核心价值
- 解决 “数据不足” 问题:你的任务可能只有几千张样本(如自定义猫狗分类),从零训练 CNN 会过拟合,但复用预训练权重,几千张样本也能训出高精度模型;
- 节省算力 / 时间:训练 ResNet18 在 ImageNet 上需要几十 / 上百 GPU 小时,个人复现几乎不可能,直接用预训练权重,几分钟就能加载完成;
- 提升模型泛化能力:预训练学到的通用特征,能让模型适应不同场景的图像(比如不同角度的猫、不同光线的狗);
- 降低入门门槛:不用从零设计模型、调参,基于预训练模型就能快速落地任务。
4. 常用预训练模型(PyTorch 内置)
| 模型名 | 特点 | 适用场景 |
|---|---|---|
| ResNet18/34 | 轻量、速度快、精度适中 | 中小数据集、普通分类任务 |
| ResNet50/101 | 精度高、参数量大 | 高精度要求、大数据集 |
| MobileNetV2 | 超轻量、移动端适配 | 部署场景(低算力) |
| VGG16/19 | 结构简单、特征提取能力强 | 学术研究、特征提取 |
二、核心预训练策略
策略 1:纯特征提取(Freeze All Backbone)
1. 定义
冻结预训练模型的所有主干层(卷积层、Transformer 层等),仅训练新增的 “分类头 / 任务头”(全连接层)—— 主干层只负责提取通用特征,不做任何修改。
2. 适用场景
- 数据集极小(几千张样本,如小批量的猫狗分类、自定义手写字符);
- 新任务与预训练数据集(如 ImageNet)差异大(如 MNIST 手写数字 vs ImageNet 自然图像);
- 算力有限(CPU / 低配 GPU),无法承担大量计算。
3. 实操方法
import torch import torch.nn as nn from torchvision import models # 加载ResNet18预训练模型 model = models.resnet18(pretrained=True) # 核心:冻结所有主干层参数(不计算梯度) for param in model.parameters(): param.requires_grad = False # 仅修改并训练分类头 in_features = model.fc.in_features model.fc = nn.Linear(in_features, 2) # 适配猫狗分类(2类) # 优化器:仅优化分类头参数(主干层无梯度,无需优化) optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-3)4. 优缺点
| 优点 | 缺点 |
|---|---|
| 训练速度极快(仅训少量参数) | 无法适配新任务的专属特征,精度上限低 |
| 完全避免过拟合(主干层无更新) | 对差异大的任务,通用特征可能不适用 |
| 算力要求极低(CPU 也能训) | - |
策略 2:分层微调(Unfreeze Top Layers)
1. 定义
不冻结全部主干层,仅解冻预训练模型的后几层(高层),前几层(低层)保持冻结 —— 因为:
- 低层(前几层):学习的是通用特征(边缘、纹理、颜色),所有图像任务都适用,无需修改;
- 高层(后几层):学习的是专属特征(物体部件、场景),需要适配新任务。
2. 适用场景
- 数据集中等(几万张样本,如常规的猫狗分类、花卉分类);
- 新任务与预训练数据集有一定相似度(如自然图像分类 vs ImageNet);
- 算力中等(入门级 GPU,如 RTX 3060)。
3. 实操方法
model = models.resnet18(pretrained=True) # 核心:仅解冻最后2个卷积块(高层),冻结前几层 # ResNet18的层结构:conv1 → layer1 → layer2 → layer3 → layer4 → fc for name, param in model.named_parameters(): # 仅解冻layer3、layer4(高层) if "layer3" in name or "layer4" in name: param.requires_grad = True else: param.requires_grad = False # 修改分类头 model.fc = nn.Linear(model.fc.in_features, 2) # 优化器:分层设置学习率(高层小学习率,分类头大学习率) optimizer = torch.optim.Adam([ {"params": model.layer3.parameters(), "lr": 1e-4}, # 高层:小学习率(避免破坏预训练权重) {"params": model.layer4.parameters(), "lr": 1e-4}, {"params": model.fc.parameters(), "lr": 1e-3} # 分类头:大学习率(全新层) ])4. 优缺点
| 优点 | 缺点 |
|---|---|
| 平衡精度和速度(仅训部分参数) | 需要调试 “解冻层数”(如解冻 2 层 / 3 层),无统一标准 |
| 适配任务专属特征,精度显著提升 | 比纯特征提取稍费算力 |
| 不易过拟合(前几层仍冻结) | - |
策略 3:全量微调(Unfreeze All Layers)
1. 定义
解冻预训练模型的所有层,主干层 + 分类头一起训练 —— 让预训练模型在保留通用特征的基础上,完全适配新任务的专属特征。
2. 适用场景
- 数据集大(几十万 / 百万张样本,如大规模电商商品分类);
- 新任务与预训练数据集高度相似(如动物分类 vs ImageNet);
- 算力充足(中高端 GPU,如 RTX 4090/A100)。
3. 实操方法
model = models.resnet18(pretrained=True) # 核心:解冻所有层(默认requires_grad=True,无需额外设置) # for param in model.parameters(): # param.requires_grad = True # 修改分类头 model.fc = nn.Linear(model.fc.in_features, 2) # 优化器:全量小学习率(关键!避免破坏预训练权重) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 比分类头单独训小10倍4. 优缺点
| 优点 | 缺点 |
|---|---|
| 精度上限最高(完全适配新任务) | 训练速度慢(训全部参数),算力要求高 |
| 能挖掘任务的专属特征 | 易过拟合(数据集小时) |
| - | 易破坏预训练的通用特征(学习率过大时) |
策略 4:增量预训练(Domain Adaptation)
1. 定义
先在新任务的 “领域数据集”上对预训练模型做 “增量训练”(仅训主干层,不训分类头),再冻结主干层训练分类头 —— 解决 “预训练数据集与新任务领域差异大” 的问题。
2. 适用场景
- 新任务领域特殊(如医学影像、遥感图像、工业缺陷检测),与 ImageNet 差异极大;
- 有一定规模的 “领域无标签 / 有标签数据”(如几千张医学影像)。
3. 实操方法
# 步骤1:加载预训练模型,冻结分类头,增量训练主干层 model = models.resnet18(pretrained=True) # 冻结分类头(仅训主干层) for param in model.fc.parameters(): param.requires_grad = False # 用领域数据集(如医学影像)训练主干层(适配领域特征) optimizer = torch.optim.Adam(model.parameters(), lr=1e-4) # 训练若干轮(如5轮)→ 主干层适配医学影像特征 # 步骤2:冻结主干层,训练分类头(医学影像分类) for param in model.parameters(): param.requires_grad = False model.fc = nn.Linear(model.fc.in_features, 5) # 5类医学影像 optimizer = torch.optim.Adam(model.fc.parameters(), lr=1e-3) # 训练分类头4. 优缺点
| 优点 | 缺点 |
|---|---|
| 解决 “领域差异大” 的问题,精度显著提升 | 需要额外的领域数据集 |
| 保留预训练通用特征,同时适配领域特征 | 多一轮训练,耗时更长 |