1. 预训练概念:在大规模数据上训练模型学习通用知识,再迁移到下游任务微调
2. 常见模型:图像有AlexNet、ResNet、ViT;NLP有BERT、GPT
3. 图像模型发展:从手工特征到深度学习,从CNN到Transformer、多模态
4. 预训练策略:数据增强、自监督/监督训练、模型微调、多模态学习
作业1.
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import time
import warnings
# 依赖库加载与配置
%pip install tqdm # 进度条工具
from tqdm import tqdm
warnings.filterwarnings("ignore") # 忽略警告信息
### 数据处理模块 ###
def get_cifar10_data(batch=128, img_size=32):
"""
构建CIFAR-10数据集加载器
:param batch: 批量大小
:param img_size: 图像缩放尺寸
:return: 训练/测试数据加载器
"""
print(f"[数据准备] 图像尺寸调整为 {img_size}x{img_size}")
# 训练集增强策略
train_trans = transforms.Compose([
transforms.Resize(img_size), # 尺寸统一
transforms.RandomCrop(img_size, padding=4),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])
# 测试集标准化处理
test_trans = transforms.Compose([
transforms.Resize(img_size),
transforms.ToTensor(),
transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])
# 数据集实例化
train_data = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_trans)
test_data = datasets.CIFAR10(root='./data', train=False, transform=test_trans)
# 数据加载器配置
train_loader = DataLoader(train_data, batch_size=batch, shuffle=True, num_workers=2, pin_memory=True)
test_loader = DataLoader(test_data, batch_size=batch, shuffle=False, num_workers=2, pin_memory=True)
print("[数据] 加载完成")
return train_loader, test_loader
### 模型构建模块 ###
def build_resnet18(pretrain=True, class_num=10):
"""构建ResNet18模型(带迁移学习)"""
# 加载预训练模型
model = models.resnet18(weights=models.ResNet18_Weights.IMAGENET1K_V1 if pretrain else None)
# 替换分类层
last_dim = model.fc.in_features
model.fc = nn.Linear(last_dim, class_num)
return model
def build_mobilenet(pretrain=True, class_num=10):
"""构建MobileNetV2轻量级模型"""
model = models.mobilenet_v2(weights=models.MobileNet_V2_Weights.IMAGENET1K_V1 if pretrain else None)
# 调整分类器输出维度
last_dim = model.classifier[1].in_features
model.classifier[1] = nn.Linear(last_dim, class_num)
return model
### 训练与评估模块 ###
def run_training(model_tag, model_builder, device, total_epochs, freeze_epochs):
"""
执行完整训练流程
:param model_tag: 模型标识名称
:param model_builder: 模型构建函数
:param device: 计算设备(CPU/GPU)
:param total_epochs: 总训练轮次
:param freeze_epochs: 冻结预训练层的轮次
"""
print(f"\n{'='*30} 开始实验: {model_tag} {'='*30}")
# 1. 准备数据与模型
train_loader, test_loader = get_cifar10_data()
model = model_builder(pretrained=True, class_num=10).to(device)
# 统计模型参数量
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"[模型] 总参数量: {total_params / 1e6:.2f}M")
# 2. 迁移学习参数冻结控制
def set_param_freeze(freeze_flag):
"""冻结/解冻模型参数"""
action = "冻结" if freeze_flag else "解冻"
print(f"[参数控制] {action} 特征提取层")
for name, param in model.named_parameters():
# 分类层始终可训练
if 'fc' not in name and 'classifier' not in name:
param.requires_grad = not freeze_flag
set_param_freeze(freeze=True) # 初始冻结特征提取层
# 优化器配置
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=1e-3)
loss_fn = nn.CrossEntropyLoss()
lr_scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', factor=0.2, patience=2, verbose=True)
# 3. 训练主循环
start_time = time.time()
for epoch in range(1, total_epochs + 1):
# 解冻控制(在指定轮次后解冻全部参数)
if epoch == freeze_epochs + 1:
set_param_freeze(freeze=False)
# 解冻后使用更小学习率
optimizer = optim.Adam(model.parameters(), lr=1e-4)
print("[优化器] 已更新为全局微调模式")
# 训练阶段
model.train()
train_loop = tqdm(train_loader, desc=f"[训练] Epoch {epoch}/{total_epochs}", leave=False)
for inputs, targets in train_loop:
inputs, targets = inputs.to(device), targets.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = loss_fn(outputs, targets)
loss.backward()
optimizer.step()
train_loop.set_postfix(loss=loss.item())
train_loop.close()
# 评估阶段
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for inputs, targets in test_loader:
inputs, targets = inputs.to(device), targets.to(device)
outputs = model(inputs)
test_loss += loss_fn(outputs, targets).item() * inputs.size(0)
preds = outputs.argmax(dim=1)
correct += preds.eq(targets).sum().item()
# 结果统计
avg_loss = test_loss / len(test_loader.dataset)
accuracy = 100. * correct / len(test_loader.dataset)
print(f"[评估] Epoch {epoch} | 测试损失: {avg_loss:.4f} | 准确率: {accuracy:.2f}%")
# 学习率调度
lr_scheduler.step(avg_loss)
# 实验完成统计
end_time = time.time()
print(f"[实验] {model_tag} 完成,总耗时: {end_time - start_time:.2f} 秒")
print(f"{'='*70}\n")
### 主程序执行 ###
if __name__ == "__main__":
# 设备配置
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"[系统] 使用设备: {DEVICE}")
# 训练参数
TOTAL_EPOCHS = 10
FREEZE_EPOCHS = 3 # 前3轮冻结特征提取层
# 运行ResNet18实验
run_training("ResNet18实验", build_resnet18, DEVICE, TOTAL_EPOCHS, FREEZE_EPOCHS)
# 运行MobileNetV2实验
run_training("MobileNetV2实验", build_mobilenet, DEVICE, TOTAL_EPOCHS, FREEZE_EPOCHS)