DAY44 PYTHON 预训练模型

预训练模型

知识点回顾

  1. 预训练的概念
  2. 常见的分类预训练模型
  3. 图像预训练模型的发展史
  4. 预训练的策略
  5. 预训练代码实战:resnet18

作业

  1. 尝试在cifar10对比如下其他的预训练模型,观察差异,尽可能和他人选择的不同
  2. 尝试通过ctrl进入resnet的内部,观察残差究竟是什么

知识点 1:预训练(Pre-training)的概念

预训练是深度学习中的一种迁移学习策略,核心逻辑是 "先通用学习,再特定任务适配",具体定义和价值如下:

核心定义:在大规模通用数据集(如 ImageNet)上,先训练一个基础模型,让模型学习到通用的特征提取能力(如边缘、纹理、物体部件等);之后将这个 "预训练好的模型" 作为起点,在小规模特定任务数据集(如自己的分类任务)上进行微调(Fine-tuning),以快速适配目标任务。

本质区别:与 "从零训练(Training from Scratch)" 相比,预训练相当于让模型 "站在巨人的肩膀上"------ 无需从原始像素开始学习基础特征,直接复用通用特征,再优化任务相关的特定特征。

核心价值:

解决小数据问题:当目标任务数据量较小时,从零训练易过拟合,预训练的通用特征可提供有效初始化,提升模型泛化能力;

降低计算成本:大规模数据集预训练需大量算力,但一次预训练可多次复用(微调成本远低于从头训练);

提升模型性能:通用数据集包含更丰富的特征模式,预训练模型的初始参数更优,微调后易达到更高精度。

python 复制代码
| **模型**       | **年份** | **提出团队**       | **关键创新点**                                                                 | **层数** | **参数量** | **ImageNet Top-5错误率** | **典型应用场景**               | **预训练权重可用性**         |
|----------------|----------|--------------------|--------------------------------------------------------------------------------|----------|------------|--------------------------|------------------------------|------------------------------|
| **LeNet-5**    | 1998     | Yann LeCun等       | 首个CNN架构,卷积层+池化层+全连接层,Sigmoid激活函数                          | 7        | ~60K       | N/A                      | 手写数字识别(MNIST)         | 无(历史模型)               |
| **AlexNet**    | 2012     | Alex Krizhevsky等  | ReLU激活函数、Dropout、数据增强、GPU训练                                        | 8        | 60M        | 15.3%                    | 大规模图像分类               | PyTorch/TensorFlow官方支持   |
| **VGGNet**     | 2014     | Oxford VGG团队     | 统一3×3卷积核、多尺度特征提取、结构简洁                                         | 16/19    | 138M/144M  | 7.3%/7.0%                | 图像分类、目标检测基础骨干网络 | PyTorch/TensorFlow官方支持   |
| **GoogLeNet**  | 2014     | Google             | Inception模块(多分支并行卷积)、1×1卷积降维、全局平均池化                     | 22       | 5M         | 6.7%                     | 大规模图像分类               | PyTorch/TensorFlow官方支持   |
| **ResNet**     | 2015     | 何恺明等           | 残差连接(解决梯度消失)、Batch Normalization                                   | 18/50/152| 11M/25M/60M | 3.57%/3.63%/3.58%        | 图像/视频分类、检测、分割     | PyTorch/TensorFlow官方支持   |
| **DenseNet**   | 2017     | Gao Huang等        | 密集连接(每层与后续所有层相连)、特征复用、参数效率高                         | 121/169  | 8M/14M     | 2.80%                    | 小数据集、医学图像处理        | PyTorch/TensorFlow官方支持   |
| **MobileNet**  | 2017     | Google             | 深度可分离卷积(减少75%计算量)、轻量级设计                                     | 28       | 4.2M       | 7.4%                     | 移动端图像分类/检测           | PyTorch/TensorFlow官方支持   |
| **EfficientNet** | 2019   | Google             | 复合缩放(同时优化深度、宽度、分辨率)、NAS搜索最佳配置                         | B0-B7    | 5.3M-66M   | 2.6% (B7)                | 高精度图像分类(资源受限场景)| PyTorch/TensorFlow官方支持   |

上图的层数,代表该模型不同的版本resnet有resnet18、resnet50、resnet152;efficientnet有efficientnet-b0、efficientnet-b1、efficientnet-b2、efficientnet-b3、efficientnet-b4等


其中ImageNet Top - 5 准确率是图像分类任务里的一种评估指标 ,用于衡量模型在 ImageNet 数据集上的分类性能,模型对图像进行分类预测,输出所有类别(共 1000 类 )的概率,取概率排名前五的类别,只要这五个类别里包含人工标注的正确类别,就算预测正确。

模型架构演进关键点总结

1. **深度突破**:从LeNet的7层到ResNet152的152层,残差连接解决了深度网络的训练难题。  ----没上过我复试班cv部分的自行去了解下什么叫做残差连接,很重要!
2. **计算效率**:GoogLeNet(Inception)和MobileNet通过结构优化,在保持精度的同时大幅降低参数量。  
3. **特征复用**:DenseNet的密集连接设计使模型能更好地利用浅层特征,适合小数据集。  
4. **自动化设计**:EfficientNet使用神经架构搜索(NAS)自动寻找最优网络配置,开创了AutoML在CNN中的应用。  


预训练模型使用建议

| **任务需求**               | **推荐模型**       | **理由**                                                                 |
|----------------------------|--------------------|--------------------------------------------------------------------------|
| 快速原型开发               | ResNet50/18        | 结构平衡,预训练权重稳定,社区支持完善                                   |
| 移动端部署                 | MobileNetV3        | 参数量小,计算高效,专为移动设备优化                                     |
| 高精度分类(资源充足)     | EfficientNet-B7    | 目前ImageNet准确率领先,适合GPU/TPU环境                                 |
| 小数据集或特征复用需求     | DenseNet           | 密集连接设计减少过拟合,特征复用能力强                                   |
| 多尺度特征提取             | Inception-ResNet   | 结合Inception多分支和ResNet残差连接,适合复杂场景                        |

这些模型的预训练权重均可通过主流框架(如PyTorch的`torchvision.models`、Keras的`applications`模块)直接加载,便于快速迁移到新任务。

预训练的效果依赖于 "数据、任务、模型、训练" 四大维度的策略设计,核心策略如下:

数据策略:决定预训练的 "特征通用性"

数据集选择:优先选择 "规模大、分布广、与目标任务相似" 的数据集(如通用任务用 ImageNet-1K/21K,医学图像用 CheXpert,遥感图像用 NWPU-RESISC45);

**数据增强:**通过随机翻转、裁剪、旋转、颜色抖动、MixUp/CutMix 等增强,扩大数据多样性,避免预训练模型过拟合(如 ImageNet 预训练常用 "随机水平翻转 + 随机裁剪");

数据清洗: 剔除数据集中的标注错误(如 ImageNet 存在约 5% 标注错误),避免错误信息影响预训练特征质量。

任务策略:决定预训练的 "特征导向"

**监督预训练(传统):**以 "图像分类" 为预训练任务(如给模型输入图像,输出 1000 类标签),学习 "从图像到类别" 的判别性特征,适合后续分类、检测等判别性任务;

自监督预训练(当前主流): 无需人工标注,让模型从无标签数据中自学习特征,更适合数据稀缺场景,常见任务包括:

对比学习(如 MoCo、SimCLR):通过 "同一图像的不同增强版本为正样本,其他图像为负样本",让模型学习相似图像的特征聚集;

掩码建模(如 MAE、BEiT):随机掩码部分图像 patch(如掩码 75%),让模型预测掩码区域的像素或语义,学习全局特征关联;

对比学习适合细粒度特征,掩码建模适合全局特征,当前大型预训练模型(如 ViT-L/16)多采用 "自监督预训练 + 监督微调" 的两步策略。

模型策略:决定预训练的 "特征提取能力"

模型初始化:优先选择已验证的基础架构(如 ResNet18/50、ViT-B),避免从零设计复杂模型(风险高、成本大);

正则化策略:加入 Dropout(随机失活)、Weight Decay(权重衰减)、Label Smoothing(标签平滑),防止预训练模型过拟合;

模型适配:根据数据集分辨率调整模型输入尺寸(如 ImageNet 预训练输入 224x224,高分辨率任务预训练输入 384x384)。

训练策略:决定预训练的 "收敛效率与稳定性"

优化器选择:常用 SGD(带动量,如 momentum=0.9)或 AdamW(适合 Transformer,权重衰减集成在优化器中);

学习率调度:采用 "余弦退火" 或 "阶梯衰减"(如 ImageNet 预训练用 "初始学习率 0.1,每 30 轮衰减为 1/10"),避免学习率过高导致不收敛或过低导致收敛慢;

批次大小(Batch Size):尽可能大(如 ImageNet 预训练用 256/512 batch),配合梯度累积(Gradient Accumulation)解决显存不足问题,提升训练稳定性。

ResNet18 的预训练完整代码(以 "CIFAR-10 数据集" 为例,模拟小规模通用数据集预训练,后续可微调至其他任务):
步骤 1:环境准备与导入库

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torchvision.models import resnet18  # PyTorch内置ResNet18
import matplotlib.pyplot as plt

# 设备配置(GPU优先)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(f"使用设备:{device}")

步骤 2:数据加载与增强(CIFAR-10 数据集,10 类,5 万训练图)

python 复制代码
# 数据增强:训练集用强增强,验证集仅Resize和归一化
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(224),  # 随机裁剪到224x224(ResNet输入尺寸)
    transforms.RandomHorizontalFlip(p=0.5),  # 随机水平翻转
    transforms.ColorJitter(brightness=0.2, contrast=0.2),  # 颜色抖动
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],  # ImageNet均值(通用归一化)
                         std=[0.229, 0.224, 0.225])
])

val_transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225])
])

# 加载数据集
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=train_transform)
val_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=val_transform)

# 数据加载器
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4)
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False, num_workers=4)

步骤 3:定义 ResNet18 模型(修改输出层适配 CIFAR-10)

PyTorch 内置的 ResNet18 默认输出 1000 类(适配 ImageNet),需修改最后全连接层为 10 类(CIFAR-10):

python 复制代码
def build_resnet18(num_classes=10):
    # 加载预训练权重(可选:若已有预训练权重,可加载后微调;此处为"从零预训练",故pretrained=False)
    model = resnet18(pretrained=False)
    # 修改最后一层全连接层(输入维度512,输出维度num_classes)
    in_features = model.fc.in_features
    model.fc = nn.Linear(in_features, num_classes)
    return model.to(device)

# 初始化模型
model = build_resnet18(num_classes=10)

步骤 4:配置预训练参数(损失函数、优化器、学习率调度)

python 复制代码
# 1. 损失函数:分类任务用交叉熵损失
criterion = nn.CrossEntropyLoss()

# 2. 优化器:SGD+动量+权重衰减
optimizer = optim.SGD(model.parameters(), lr=0.1, momentum=0.9, weight_decay=5e-4)

# 3. 学习率调度:每15轮衰减为原来的0.1
lr_scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=15, gamma=0.1)

步骤 5:预训练循环(训练 + 验证)

python 复制代码
def train_one_epoch(model, train_loader, criterion, optimizer, device):
    model.train()  # 训练模式(启用Dropout等)
    total_loss = 0.0
    total_correct = 0
    total_samples = 0
    
    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)
        
        # 前向传播
        outputs = model(images)
        loss = criterion(outputs, labels)
        
        # 反向传播与优化
        optimizer.zero_grad()  # 清空梯度
        loss.backward()        # 计算梯度
        optimizer.step()       # 更新参数
        
        # 统计指标
        total_loss += loss.item() * images.size(0)
        _, predicted = torch.max(outputs, 1)  # 取预测概率最大的类别
        total_correct += (predicted == labels).sum().item()
        total_samples += images.size(0)
    
    # 计算 epoch 级指标
    avg_loss = total_loss / total_samples
    accuracy = total_correct / total_samples
    return avg_loss, accuracy

def validate(model, val_loader, criterion, device):
    model.eval()  # 验证模式(关闭Dropout等)
    total_loss = 0.0
    total_correct = 0
    total_samples = 0
    
    with torch.no_grad():  # 禁用梯度计算,节省显存和时间
        for images, labels in val_loader:
            images, labels = images.to(device), labels.to(device)
            outputs = model(images)
            loss = criterion(outputs, labels)
            
            # 统计指标
            total_loss += loss.item() * images.size(0)
            _, predicted = torch.max(outputs, 1)
            total_correct += (predicted == labels).sum().item()
            total_samples += images.size(0)
    
    avg_loss = total_loss / total_samples
    accuracy = total_correct / total_samples
    return avg_loss, accuracy

# 开始预训练(共50轮)
num_epochs = 50
train_losses, train_accs = [], []
val_losses, val_accs = [], []

for epoch in range(num_epochs):
    print(f"Epoch [{epoch+1}/{num_epochs}]")
    
    # 训练
    train_loss, train_acc = train_one_epoch(model, train_loader, criterion, optimizer, device)
    train_losses.append(train_loss)
    train_accs.append(train_acc)
    print(f"Train - Loss: {train_loss:.4f}, Acc: {train_acc:.4f}")
    
    # 验证
    val_loss, val_acc = validate(model, val_loader, criterion, device)
    val_losses.append(val_loss)
    val_accs.append(val_acc)
    print(f"Val - Loss: {val_loss:.4f}, Acc: {val_acc:.4f}")
    
    # 更新学习率
    lr_scheduler.step()

# 保存预训练模型(后续可用于微调)
torch.save(model.state_dict(), "resnet18_pretrained_cifar10.pth")
print("预训练模型已保存!")

# 绘制训练曲线(可选,直观查看训练过程)
plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(train_losses, label="Train Loss")
plt.plot(val_losses, label="Val Loss")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.subplot(1, 2, 2)
plt.plot(train_accs, label="Train Acc")
plt.plot(val_accs, label="Val Acc")
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.show()

作业

python 复制代码
from torchvision.models import resnet18
import torch

# 加载ResNet-18模型
model = resnet18()
# 打印网络结构(观察layer1~layer4由残差块组成)
print(model)
相关推荐
奔跑中的小象2 小时前
统信UOS + 天数AI卡部署SGLang服务手册
人工智能·uos·sglang·天数智芯
DevSecOps选型指南2 小时前
中国版Mythos,为何是悬镜安全灵脉CodeAI?
人工智能·安全
Shockang2 小时前
LangGraph 状态机实战
人工智能
刹那芳华19922 小时前
循环神经网络的从零开始实现(RNN)
人工智能·rnn·深度学习
阿童木写作2 小时前
跨境图片翻译工具多合一,批量图片视频字幕翻译加智能抠图
人工智能·python·音视频·语音识别
科技之门2 小时前
AI3D从建模到贴图、绑骨和动画的完整流程怎么做?V2Fun完整工作流指南
人工智能·3d·贴图
宇宙第一小趴菜2 小时前
二、机器学习的应用领域和发展史
人工智能·机器学习
前端开发江鸟2 小时前
我写过 MCP Server,却一直以为 MCP 只有 Tool
人工智能
天国梦3 小时前
自习室智能化升级避坑指南:天学网AI智习室方案实测与选型建议
大数据·人工智能
阿里云云原生3 小时前
可用性从 99.9% 跃升至 99.995%:畅捷通如何用 AI 重塑运维底座?
运维·网络·人工智能