迁移学习让我们站在巨人的肩膀上——用预训练模型的知识解决新问题,用更少的数据和计算达到更好的效果。
源域(D_s) → 预训练模型 → 目标域(D_t)
底层特征(边缘、纹理)是通用的 → 高层特征是任务特定的
| 策略 | 做法 | 适用场景 |
|---|---|---|
| 特征提取 | 冻结预训练层,只训练新分类头 | 小数据集,与预训练任务相似 |
| 微调 | 小学习率更新全部或部分层 | 中等数据集,或任务差异大 |
import torch
import torch.nn as nn
import torchvision.models as models
# 迁移学习实验
torch.manual_seed(42)
# 模拟预训练模型(小规模)
class PretrainedModel(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(
nn.Linear(20, 128), nn.ReLU(),
nn.Linear(128, 128), nn.ReLU(),
nn.Linear(128, 64), nn.ReLU(),
)
self.classifier = nn.Linear(64, 5) # 5类源任务
def forward(self, x):
return self.classifier(self.features(x))
# 源任务预训练
source_model = PretrainedModel()
X_source = torch.randn(500, 20)
y_source = torch.randint(0, 5, (500,))
optimizer = torch.optim.Adam(source_model.parameters(), lr=0.001)
loss_fn = nn.CrossEntropyLoss()
for epoch in range(100):
optimizer.zero_grad()
loss = loss_fn(source_model(X_source), y_source)
loss.backward()
optimizer.step()
print("=== 源任务预训练完成 ===")
# 目标任务(3类,少数据)
X_target = torch.randn(50, 20)
y_target = torch.randint(0, 3, (50,))
# 策略1:特征提取(冻结特征层)
model_fe = PretrainedModel()
model_fe.load_state_dict(source_model.state_dict())
model_fe.classifier = nn.Linear(64, 3) # 替换分类头
# 冻结特征层
for param in model_fe.features.parameters():
param.requires_grad = False
trainable = sum(p.numel() for p in model_fe.parameters() if p.requires_grad)
total = sum(p.numel() for p in model_fe.parameters())
print(f"\n特征提取: 可训练参数={trainable:,}/{total:,} ({trainable/total*100:.1f}%)")
# 策略2:微调(小学习率)
model_ft = PretrainedModel()
model_ft.load_state_dict(source_model.state_dict())
model_ft.classifier = nn.Linear(64, 3)
# 策略3:从零训练
model_scratch = PretrainedModel()
model_scratch.classifier = nn.Linear(64, 3)
# 训练对比
for name, model, lr in [("特征提取", model_fe, 0.01), ("微调", model_ft, 0.0001), ("从零训练", model_scratch, 0.001)]:
optimizer = torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=lr)
for epoch in range(100):
optimizer.zero_grad()
loss = loss_fn(model(X_target), y_target)
loss.backward()
optimizer.step()
with torch.no_grad():
acc = (model(X_target).argmax(1) == y_target).float().mean()
print(f"{name}: 最终acc={acc.item():.2%}")
本课的核心知识点构成了CNN学习的重要一环。让我们从更高维度审视这些知识之间的关系:
⚠️ 初学者常犯的错误:
💡 最佳实践:
深度学习是一个整体——每一课的知识都不是孤立的:
💡 继续深入的学习路径:
对比ResNet18和VGG16作为特征提取器的效果。
实现渐进式解冻策略:逐层解冻微调。
当源域和目标域差异很大时,如何改进迁移学习?
⚠️ 需要避免的典型错误:
💡 提升模型性能的系统方法:
理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:
建立正确的直觉比记住公式更重要:
1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)
2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的
3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构
4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)
本课作为CNN阶段的核心内容,与前后课程紧密关联:
| 关联课程 | 关联点 | 协同效应 |
|---|---|---|
| 前序课程 | 提供了本课的基础知识 | 循序渐进的理解 |
| 后续课程 | 本课内容是后续的基础 | 逐步构建能力 |
| 平行课程 | 同一阶段的互补知识 | 多角度深入理解 |
| 实战项目 | 综合运用所有知识 | 理论与实践结合 |
💡 准备面试时,确保能回答以下问题:
掌握本课内容后,可以通过以下方式继续深入:
将本课涉及的关键公式整理如下,方便回顾和记忆。理解每个公式背后的直觉比死记硬背更重要——试着用自然语言解释每个公式在做什么。
| 概念A | 概念B | 关键区别 |
|---|---|---|
| 参数 | 超参数 | 参数通过训练学习,超参数需要手动设定 |
| 训练误差 | 泛化误差 | 训练误差衡量拟合程度,泛化误差衡量预测能力 |
| 偏差 | 方差 | 偏差是系统性误差,方差是随机波动 |
| L1正则 | L2正则 | L1产生稀疏解,L2产生平滑解 |
| BatchNorm | LayerNorm | BN沿batch维度,LN沿特征维度 |
以下是本课核心概念的标准PyTorch实现模板,可以直接用于实际项目:
💡 调试建议:当结果不符合预期时,先检查数据,再检查损失函数,最后检查模型结构。90%的问题出在前两个环节。
站在巨人的肩膀上,用更少数据达到更好效果!