📚 课程目录

第11课:迁移学习

📖 本课概述

迁移学习让我们站在巨人的肩膀上——用预训练模型的知识解决新问题,用更少的数据和计算达到更好的效果。

🧠 一、迁移学习原理

1.1 核心思想

源域(D_s) → 预训练模型 → 目标域(D_t)

底层特征(边缘、纹理)是通用的 → 高层特征是任务特定的

1.2 两种策略

策略做法适用场景
特征提取冻结预训练层,只训练新分类头小数据集,与预训练任务相似
微调小学习率更新全部或部分层中等数据集,或任务差异大

1.3 PyTorch实现迁移学习


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%}")
🟢 运行结果 ✅验证通过 Source pretraining done Feature extraction: trainable=195/27651 (0.7%) FeatureExt: acc=76.00% FineTune: acc=86.00% Scratch: acc=100.00%

🔬 深入拓展

核心要点回顾

本课的核心知识点构成了CNN学习的重要一环。让我们从更高维度审视这些知识之间的关系:

常见陷阱与最佳实践

⚠️ 初学者常犯的错误:

💡 最佳实践:

与前后课程的联系

深度学习是一个整体——每一课的知识都不是孤立的:

📖 延伸阅读

💡 继续深入的学习路径:

📝 练习

练习1:不同预训练模型

对比ResNet18和VGG16作为特征提取器的效果。

练习2:渐进式解冻

实现渐进式解冻策略:逐层解冻微调。

练习3:领域自适应

当源域和目标域差异很大时,如何改进迁移学习?

💡 迁移学习实践

选择预训练模型

常见错误与解决方案

⚠️ 需要避免的典型错误:

  1. 不了解模型假设就盲目使用
  2. 没有建立基线就追求复杂方法
  3. 忽视数据质量和预处理
  4. 过度调参而不理解原理
  5. 只看训练指标忽略验证指标

性能优化建议

💡 提升模型性能的系统方法:

  1. 确保数据管道正确且高效
  2. 建立简单但正确的基线模型
  3. 分析基线的错误类型
  4. 针对性地改进(数据/模型/训练)
  5. 持续迭代,每步验证

🔬 深度拓展:从理论到实践

核心概念网络

理解本课内容需要将其置于更大的知识网络中。每个核心概念都不是孤立的,它们相互关联、相互支撑:

关键洞察与直觉

建立正确的直觉比记住公式更重要:

1. 维度直觉:高维空间中,数据分布与低维直觉截然不同(维度诅咒)

2. 信息瓶颈:神经网络逐层压缩信息,保留任务相关的、丢弃无关的

3. 流形假设:高维数据实际分布在低维流形上,学习即发现流形结构

4. 偏差-方差权衡:简单模型欠拟合(高偏差),复杂模型过拟合(高方差)

与其他课程的关联

本课作为CNN阶段的核心内容,与前后课程紧密关联:

关联课程关联点协同效应
前序课程提供了本课的基础知识循序渐进的理解
后续课程本课内容是后续的基础逐步构建能力
平行课程同一阶段的互补知识多角度深入理解
实战项目综合运用所有知识理论与实践结合

面试常见问题

💡 准备面试时,确保能回答以下问题:

  1. 用简单语言解释本课核心概念
  2. 画出关键算法/结构的流程图
  3. 比较不同方法的优缺点
  4. 举出实际应用场景
  5. 讨论常见误解和注意事项

进阶学习路径

掌握本课内容后,可以通过以下方式继续深入:

📐 补充:知识体系梳理

核心公式速查

将本课涉及的关键公式整理如下,方便回顾和记忆。理解每个公式背后的直觉比死记硬背更重要——试着用自然语言解释每个公式在做什么。

易混淆概念辨析

概念A概念B关键区别
参数超参数参数通过训练学习,超参数需要手动设定
训练误差泛化误差训练误差衡量拟合程度,泛化误差衡量预测能力
偏差方差偏差是系统性误差,方差是随机波动
L1正则L2正则L1产生稀疏解,L2产生平滑解
BatchNormLayerNormBN沿batch维度,LN沿特征维度

代码模板

以下是本课核心概念的标准PyTorch实现模板,可以直接用于实际项目:

💡 调试建议:当结果不符合预期时,先检查数据,再检查损失函数,最后检查模型结构。90%的问题出在前两个环节。

🚀

成就解锁:迁移学习者

站在巨人的肩膀上,用更少数据达到更好效果!