制作一个网站的基本步骤,有没有专门做游戏人物的绅士视频网站,wordpress 倡萌 相册,山东外贸网站建设怎么样预训练模型CBAM模块 知识点回顾#xff1a; resnet结构解析CBAM放置位置的思考针对预训练模型的训练策略 差异化学习率三阶段微调 使用resnet的预训练策略#xff1a;先冻结预训练层#xff0c;然后训练其他层。之前的其它层是全连接层#xff08;分类头#xff09;… 预训练模型CBAM模块 知识点回顾 resnet结构解析CBAM放置位置的思考针对预训练模型的训练策略 差异化学习率三阶段微调 使用resnet的预训练策略先冻结预训练层然后训练其他层。之前的其它层是全连接层分类头现在其它层还包含了每一个残差块中的cbam注意力层。 resnet结构解析 import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 定义通道注意力
class ChannelAttention(nn.Module):def __init__(self, in_channels, ratio16):通道注意力机制初始化参数:in_channels: 输入特征图的通道数ratio: 降维比例用于减少参数量默认为16super().__init__()# 全局平均池化将每个通道的特征图压缩为1x1保留通道间的平均值信息self.avg_pool nn.AdaptiveAvgPool2d(1)# 全局最大池化将每个通道的特征图压缩为1x1保留通道间的最显著特征self.max_pool nn.AdaptiveMaxPool2d(1)# 共享全连接层用于学习通道间的关系# 先降维除以ratio再通过ReLU激活最后升维回原始通道数self.fc nn.Sequential(nn.Linear(in_channels, in_channels // ratio, biasFalse), # 降维层nn.ReLU(), # 非线性激活函数nn.Linear(in_channels // ratio, in_channels, biasFalse) # 升维层)# Sigmoid函数将输出映射到0-1之间作为各通道的权重self.sigmoid nn.Sigmoid()def forward(self, x):前向传播函数参数:x: 输入特征图形状为 [batch_size, channels, height, width]返回:调整后的特征图通道权重已应用# 获取输入特征图的维度信息这是一种元组的解包写法b, c, h, w x.shape# 对平均池化结果进行处理展平后通过全连接网络avg_out self.fc(self.avg_pool(x).view(b, c))# 对最大池化结果进行处理展平后通过全连接网络max_out self.fc(self.max_pool(x).view(b, c))# 将平均池化和最大池化的结果相加并通过sigmoid函数得到通道权重attention self.sigmoid(avg_out max_out).view(b, c, 1, 1)# 将注意力权重与原始特征相乘增强重要通道抑制不重要通道return x * attention #这个运算是pytorch的广播机制## 空间注意力模块
class SpatialAttention(nn.Module):def __init__(self, kernel_size7):super().__init__()self.conv nn.Conv2d(2, 1, kernel_size, paddingkernel_size//2, biasFalse)self.sigmoid nn.Sigmoid()def forward(self, x):# 通道维度池化avg_out torch.mean(x, dim1, keepdimTrue) # 平均池化(B,1,H,W)max_out, _ torch.max(x, dim1, keepdimTrue) # 最大池化(B,1,H,W)pool_out torch.cat([avg_out, max_out], dim1) # 拼接(B,2,H,W)attention self.conv(pool_out) # 卷积提取空间特征return x * self.sigmoid(attention) # 特征与空间权重相乘## CBAM模块
class CBAM(nn.Module):def __init__(self, in_channels, ratio16, kernel_size7):super().__init__()self.channel_attn ChannelAttention(in_channels, ratio)self.spatial_attn SpatialAttention(kernel_size)def forward(self, x):x self.channel_attn(x)x self.spatial_attn(x)return x
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import matplotlib.pyplot as plt
import numpy as np# 设置中文字体支持
plt.rcParams[font.family] [SimHei]
plt.rcParams[axes.unicode_minus] False # 解决负号显示问题# 检查GPU是否可用
device torch.device(cuda if torch.cuda.is_available() else cpu)
print(f使用设备: {device})# 数据预处理与原代码一致
train_transform transforms.Compose([transforms.RandomCrop(32, padding4),transforms.RandomHorizontalFlip(),transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.1),transforms.RandomRotation(15),transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])test_transform transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))
])# 加载数据集与原代码一致
train_dataset datasets.CIFAR10(root./data, trainTrue, downloadTrue, transformtrain_transform)
test_dataset datasets.CIFAR10(root./data, trainFalse, transformtest_transform)
train_loader DataLoader(train_dataset, batch_size64, shuffleTrue)
test_loader DataLoader(test_dataset, batch_size64, shuffleFalse) import torch
import torchvision.models as models
from torchinfo import summary #之前的内容说了推荐用他来可视化模型结构信息最全# 加载 ResNet18预训练
model models.resnet18(pretrainedTrue)
model.eval()# 输出模型结构和参数概要
summary(model, input_size(1, 3, 224, 224)) 经典的 ResNet-18 模型可以将其看作一个处理流水线图像数据从一端进去分类结果从另一端出来。整个过程可以分为三个主要部分 输入预处理Stem对应层级为 Conv2d:1-1 到 MaxPool2d:1-4主要作用是对输入图像进行初步的特征提取并通过池化操作将特征图尺寸减半为后续处理做准备。核心特征提取对应层级为四个 Sequential 模块1-5 到 1-8这是网络的主体由多个残差块BasicBlock堆叠而成负责从浅到深、从粗到细地学习图像特征。分类输出Head对应层级为 AdaptiveAvgPool2d:1-9 和 Linear:1-10主要作用是将最终的特征图feature map转换成一个特征向量并通过全连接层映射到最终的 1000 个类别上。 将CBAM插入resnet的放置位置 预训练模型的训练策略
介绍一种比较适合这里的预训练策略
1. 阶段 1epoch 1-5
仅解冻分类头fc和所有 CBAM 模块冻结 ResNet18 的主干卷积层layer1-4。
目标先让模型通过预训练特征学习新任务的分类边界同时微调注意力模块。
学习率1e-3较高学习率加速分类头收敛。
阶段 2epoch 6-20
解冻高层卷积层layer3、layer4 分类头 CBAM冻结低层卷积层layer1、layer2。
目标释放高层语义特征如 “物体类别” 相关层适应新任务的抽象表示。
学习率1e-4降低学习率避免破坏预训练权重。
阶段 3epoch 21-50
解冻所有层包括低层卷积层 layer1、layer2端到端微调。
目标让底层特征如边缘、纹理与新任务对齐提升特征表达能力。
学习率1e-5最小学习率缓慢调整全局参数。
2. CBAM 模块集成
在每个残差块组layer1-4输出后添加 CBAM确保注意力机制作用于各阶段特征图且不影响残差块内部的跳连接。
CBAM 参数默认使用ratio16和kernel_size7可根据计算资源调整如减小ratio以降低参数量。
3. 学习率与优化器
使用Adam优化器分阶段手动调整学习率也可配合自动调度器如CosineAnnealingLR。
每次解冻新层时学习率降低一个数量级避免梯度冲击预训练权重。
预期效果与监控
阶段 1测试准确率应逐步提升至 20%-40%摆脱随机猜测损失开始下降。
阶段 2准确率加速提升利用高层特征可能达到 60%-80%。
阶段 3准确率缓慢提升并收敛底层特征微调最终可能超过 85%取决于 CIFAR10 的基线表现。
监控重点
若阶段 1 准确率仍为 9%检查数据预处理或标签是否正确。
若阶段 2 后准确率停滞尝试增加正则化如在 CBAM 后添加 Dropout或调整 CBAM 参数。 import time#
# 4. 结合了分阶段策略和详细打印的训练函数
#
def set_trainable_layers(model, trainable_parts):print(f\n--- 解冻以下部分并设为可训练: {trainable_parts})for name, param in model.named_parameters():param.requires_grad Falsefor part in trainable_parts:if part in name:param.requires_grad Truebreakdef train_staged_finetuning(model, criterion, train_loader, test_loader, device, epochs):optimizer None# 初始化历史记录列表与你的要求一致all_iter_losses, iter_indices [], []train_acc_history, test_acc_history [], []train_loss_history, test_loss_history [], []for epoch in range(1, epochs 1):epoch_start_time time.time()# --- 动态调整学习率和冻结层 ---if epoch 1:print(\n *50 \n **阶段 1训练注意力模块和分类头**\n *50)set_trainable_layers(model, [cbam, backbone.fc])optimizer optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr1e-3)elif epoch 6:print(\n *50 \n✈️ **阶段 2解冻高层卷积层 (layer3, layer4)**\n *50)set_trainable_layers(model, [cbam, backbone.fc, backbone.layer3, backbone.layer4])optimizer optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr1e-4)elif epoch 21:print(\n *50 \n️ **阶段 3解冻所有层进行全局微调**\n *50)for param in model.parameters(): param.requires_grad Trueoptimizer optim.Adam(model.parameters(), lr1e-5)# --- 训练循环 ---model.train()running_loss, correct, total 0.0, 0, 0for batch_idx, (data, target) in enumerate(train_loader):data, target data.to(device), target.to(device)optimizer.zero_grad()output model(data)loss criterion(output, target)loss.backward()optimizer.step()# 记录每个iteration的损失iter_loss loss.item()all_iter_losses.append(iter_loss)iter_indices.append((epoch - 1) * len(train_loader) batch_idx 1)running_loss iter_loss_, predicted output.max(1)total target.size(0)correct predicted.eq(target).sum().item()# 按你的要求每100个batch打印一次if (batch_idx 1) % 100 0:print(fEpoch: {epoch}/{epochs} | Batch: {batch_idx1}/{len(train_loader)} f| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx1):.4f})epoch_train_loss running_loss / len(train_loader)epoch_train_acc 100. * correct / totaltrain_loss_history.append(epoch_train_loss)train_acc_history.append(epoch_train_acc)# --- 测试循环 ---model.eval()test_loss, correct_test, total_test 0, 0, 0with torch.no_grad():for data, target in test_loader:data, target data.to(device), target.to(device)output model(data)test_loss criterion(output, target).item()_, predicted output.max(1)total_test target.size(0)correct_test predicted.eq(target).sum().item()epoch_test_loss test_loss / len(test_loader)epoch_test_acc 100. * correct_test / total_testtest_loss_history.append(epoch_test_loss)test_acc_history.append(epoch_test_acc)# 打印每个epoch的最终结果print(fEpoch {epoch}/{epochs} 完成 | 耗时: {time.time() - epoch_start_time:.2f}s | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%)# 训练结束后调用绘图函数print(\n训练完成! 开始绘制结果图表...)plot_iter_losses(all_iter_losses, iter_indices)plot_epoch_metrics(train_acc_history, test_acc_history, train_loss_history, test_loss_history)# 返回最终的测试准确率return epoch_test_acc#
# 5. 绘图函数定义
#
def plot_iter_losses(losses, indices):plt.figure(figsize(10, 4))plt.plot(indices, losses, b-, alpha0.7, labelIteration Loss)plt.xlabel(IterationBatch序号)plt.ylabel(损失值)plt.title(每个 Iteration 的训练损失)plt.legend()plt.grid(True)plt.tight_layout()plt.show()def plot_epoch_metrics(train_acc, test_acc, train_loss, test_loss):epochs range(1, len(train_acc) 1)plt.figure(figsize(12, 4))plt.subplot(1, 2, 1)plt.plot(epochs, train_acc, b-, label训练准确率)plt.plot(epochs, test_acc, r-, label测试准确率)plt.xlabel(Epoch)plt.ylabel(准确率 (%))plt.title(训练和测试准确率)plt.legend(); plt.grid(True)plt.subplot(1, 2, 2)plt.plot(epochs, train_loss, b-, label训练损失)plt.plot(epochs, test_loss, r-, label测试损失)plt.xlabel(Epoch)plt.ylabel(损失值)plt.title(训练和测试损失)plt.legend(); plt.grid(True)plt.tight_layout()plt.show()#
# 6. 执行训练
#
model ResNet18_CBAM().to(device)
criterion nn.CrossEntropyLoss()
epochs 50print(开始使用带分阶段微调策略的ResNet18CBAM模型进行训练...)
final_accuracy train_staged_finetuning(model, criterion, train_loader, test_loader, device, epochs)
print(f训练完成最终测试准确率: {final_accuracy:.2f}%)# torch.save(model.state_dict(), resnet18_cbam_finetuned.pth)
# print(模型已保存为: resnet18_cbam_finetuned.pth) torch.save(model.state_dict(), resnet18_cbam_finetuned.pth)
print(模型已保存为: resnet18_cbam_finetuned.pth)
浙大疏锦行