Python打卡训练营学习记录Day50

DAY 50 预训练模型+CBAM模块

知识点回顾:

  1. resnet结构解析
  2. CBAM放置位置的思考
  3. 针对预训练模型的训练策略
    1. 差异化学习率
    2. 三阶段微调 

ps:今日的代码训练时长较长,3080ti大概需要40min的训练时长

作业:

  1. 好好理解下resnet18的模型结构
  2. 尝试对vgg16+cbam进行微调策略

    ResNet18 模型结构理解ResNet18 模型结构理解
    ResNet(残差网络)通过引入残差块解决了深层网络的梯度消失问题,使网络可以训练更深。ResNet18 包含 18 层(1 个卷积层 + 17 个卷积层或全连接层),具体结构如下:

输入层:接收 224×224×3 的图像
初始卷积层:7×7 卷积,64 通道,步长 2,随后 BatchNorm 和 ReLU
4 个残差模块组:每个模块组包含多个残差块(BasicBlock)
残差块结构为:3×3 卷积 → BatchNorm → ReLU → 3×3 卷积 → BatchNorm → 残差连接 → ReLU
全局平均池化:将特征图压缩为 1×1 特征向量全连接层:输出分类结果
VGG16+CBAM 微调策略
CBAM(卷积注意力模块)可以增强特征表达能力,将其应用于 VGG16 时,可以放置在每个卷积组之后。以下是针对 VGG16+CBAM 的三阶段微调策略:

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models
from torch.optim.lr_scheduler import StepLR
 
# 定义 CBAM 模块
class ChannelAttention(nn.Module):
    def __init__(self, in_channels, reduction_ratio=16):
        super(ChannelAttention, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)
        
        self.fc = nn.Sequential(
            nn.Conv2d(in_channels, in_channels // reduction_ratio, 1, bias=False),
            nn.ReLU(),
            nn.Conv2d(in_channels // reduction_ratio, in_channels, 1, bias=False)
        )
        
    def forward(self, x):
        avg_out = self.fc(self.avg_pool(x))
        max_out = self.fc(self.max_pool(x))
        out = avg_out + max_out
        return torch.sigmoid(out)
 
class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
        self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2, bias=False)
        
    def forward(self, x):
        avg_out = torch.mean(x, dim=1, keepdim=True)
        max_out, _ = torch.max(x, dim=1, keepdim=True)
        out = torch.cat([avg_out, max_out], dim=1)
        out = self.conv(out)
        return torch.sigmoid(out)
 
class CBAM(nn.Module):
    def __init__(self, in_channels, reduction_ratio=16, kernel_size=7):
        super(CBAM, self).__init__()
        self.channel_att = ChannelAttention(in_channels, reduction_ratio)
        self.spatial_att = SpatialAttention(kernel_size)
        
    def forward(self, x):
        x = x * self.channel_att(x)
        x = x * self.spatial_att(x)
        return x
 
# 修改 VGG16 模型,添加 CBAM
def vgg16_cbam(pretrained=True):
    model = models.vgg16(pretrained=pretrained)
    
    # 在每个 block 后添加 CBAM
    features = list(model.features)
    new_features = []
    
    # VGG16 的 block 划分点
    block_end_indices = [4, 9, 16, 23, 30]
    current_block = 0
    
    for i, layer in enumerate(features):
        new_features.append(layer)
        if i == block_end_indices[current_block] and current_block < len(block_end_indices) - 1:
            # 除了最后一个 block,其他都添加 CBAM
            in_channels = list(filter(lambda x: isinstance(x, nn.Conv2d), features[:i+1]))[-1].out_channels
            new_features.append(CBAM(in_channels))
            current_block += 1
    
    model.features = nn.Sequential(*new_features)
    return model
 
# 三阶段微调策略
def train_vgg16_cbam():
    # 阶段 1: 冻结除最后几层外的所有参数
    model = vgg16_cbam(pretrained=True)
    
    # 冻结大部分参数
    for param in list(model.parameters())[:-20]:
        param.requires_grad = False
    
    optimizer = optim.SGD(filter(lambda p: p.requires_grad, model.parameters()), lr=0.001, momentum=0.9)
    scheduler = StepLR(optimizer, step_size=5, gamma=0.1)
    
    # 训练前 10 个 epoch
    for epoch in range(10):
        # 训练代码
        scheduler.step()
    
    # 阶段 2: 解冻更多层,使用差异化学习率
    for param in list(model.parameters())[-40:]:
        param.requires_grad = True
    
    # 为不同层设置不同学习率
    params = [
        {'params': list(model.parameters())[:-40], 'lr': 1e-5},
        {'params': list(model.parameters())[-40:-20], 'lr': 1e-4},
        {'params': list(model.parameters())[-20:], 'lr': 1e-3}
    ]
    
    optimizer = optim.SGD(params, momentum=0.9)
    scheduler = StepLR(optimizer, step_size=5, gamma=0.1)
    
    # 训练 10-20 个 epoch
    for epoch in range(10, 20):
        # 训练代码
        scheduler.step()
    
    # 阶段 3: 解冻所有层,使用更低学习率
    for param in model.parameters():
        param.requires_grad = True
    
    optimizer = optim.SGD(model.parameters(), lr=1e-4, momentum=0.9)
    scheduler = StepLR(optimizer, step_size=5, gamma=0.1)
    
    # 训练 20-30 个 epoch
    for epoch in range(20, 30):
        # 训练代码
        scheduler.step()
    
    return model

策略解释
模型修改:在 VGG16 的每个卷积组后添加 CBAM 模块,增强特征表达能力。

三阶段微调:

阶段 1:冻结大部分预训练参数,仅训练最后几层和 CBAM 模块,防止灾难性遗忘。
阶段 2:解冻更多层,使用差异化学习率(底层小学习率,高层大学习率),微调中间层特征。
阶段 3:解冻所有层,使用低学习率全局微调,进一步优化模型。
学习率调整:使用 StepLR 调度器,每 5 个 epoch 降低学习率,有助于模型收敛。
@浙大疏锦行

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值