珠海低价网站建设,网龙网络公司地址,网站开发的需要的技术人员,网站建设微信商城运营DAY 52 神经网络调参指南 知识点回顾#xff1a; 随机种子内参的初始化神经网络调参指南 参数的分类调参的顺序各部分参数的调整心得 作业#xff1a;对于day41的简单cnn#xff0c;看看是否可以借助调参指南进一步提高精度。 day41的简单CNN最后的结果#xff0c;今天要做…DAY 52 神经网络调参指南 知识点回顾 随机种子内参的初始化神经网络调参指南 参数的分类调参的顺序各部分参数的调整心得 作业对于day41的简单cnn看看是否可以借助调参指南进一步提高精度。 day41的简单CNN最后的结果今天要做的是使用调参指南中的方法进一步提高精度 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})# 1. 数据预处理
# 训练集使用多种数据增强方法提高模型泛化能力
train_transform transforms.Compose([# 随机裁剪图像从原图中随机截取32x32大小的区域transforms.RandomCrop(32, padding4),# 随机水平翻转图像概率0.5transforms.RandomHorizontalFlip(),# 随机颜色抖动亮度、对比度、饱和度和色调随机变化transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2, hue0.1),# 随机旋转图像最大角度15度transforms.RandomRotation(15),# 将PIL图像或numpy数组转换为张量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))
])# 2. 加载CIFAR-10数据集
train_dataset datasets.CIFAR10(root./data,trainTrue,downloadTrue,transformtrain_transform # 使用增强后的预处理
)test_dataset datasets.CIFAR10(root./data,trainFalse,transformtest_transform # 测试集不使用增强
)# 3. 创建数据加载器
batch_size 80
train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue)
test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse)
# 4. 定义CNN模型的定义替代原MLP
class CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 初始卷积层self.conv_init nn.Sequential(nn.Conv2d(3, 64, kernel_size3, stride1, padding1, biasFalse),nn.BatchNorm2d(64),nn.ReLU())# 第一卷积块含CBAMself.block1 nn.Sequential(nn.Conv2d(64, 64, kernel_size3, stride1, padding1, biasFalse),nn.BatchNorm2d(64),nn.ReLU(),nn.Conv2d(64, 64, kernel_size3, stride1, padding1, biasFalse),nn.BatchNorm2d(64),CBAM(64) # 在卷积块后添加CBAM)self.pool1 nn.MaxPool2d(kernel_size2, stride2)self.drop1 nn.Dropout2d(0.1)# 第二卷积块含CBAMself.block2 nn.Sequential(nn.Conv2d(64, 128, kernel_size3, stride2, padding1, biasFalse), # stride2降维nn.BatchNorm2d(128),nn.ReLU(),nn.Conv2d(128, 128, kernel_size3, stride1, padding1, biasFalse),nn.BatchNorm2d(128),CBAM(128) # 在卷积块后添加CBAM)self.pool2 nn.AvgPool2d(kernel_size2, stride2)self.drop2 nn.Dropout2d(0.2)# 第三卷积块含CBAMself.block3 nn.Sequential(nn.Conv2d(128, 256, kernel_size3, stride2, padding1, biasFalse),nn.BatchNorm2d(256),nn.ReLU(),nn.Conv2d(256, 256, kernel_size3, stride1, padding1, biasFalse),nn.BatchNorm2d(256),CBAM(256) # 在卷积块后添加CBAM)self.pool3 nn.AdaptiveAvgPool2d(4)self.drop3 nn.Dropout2d(0.3)# 全连接层self.fc nn.Sequential(nn.Linear(256 * 4 * 4, 512),nn.BatchNorm1d(512),nn.ReLU(),nn.Dropout(0.5),nn.Linear(512, 128),nn.BatchNorm1d(128),nn.ReLU(),nn.Dropout(0.3),nn.Linear(128, 10))def forward(self, x):x self.conv_init(x)x self.block1(x)x self.pool1(x)x self.drop1(x)x self.block2(x)x self.pool2(x)x self.drop2(x)x self.block3(x)x self.pool3(x)x self.drop3(x)x x.view(-1, 256 * 4 * 4)x self.fc(x)return x# 初始化模型
model CNN()
model model.to(device) # 将模型移至GPU如果可用
criterion nn.CrossEntropyLoss() # 交叉熵损失函数
optimizer optim.Adam(model.parameters(), lr0.001) # Adam优化器# 引入学习率调度器在训练过程中动态调整学习率--训练初期使用较大的 LR 快速降低损失训练后期使用较小的 LR 更精细地逼近全局最优解。
# 在每个 epoch 结束后需要手动调用调度器来更新学习率可以在训练过程中调用 scheduler.step()
scheduler optim.lr_scheduler.ReduceLROnPlateau(optimizer, # 指定要控制的优化器这里是Adammodemin, # 监测的指标是最小化如损失函数patience3, # 如果连续3个epoch指标没有改善才降低LRfactor0.5 # 降低LR的比例新LR 旧LR × 0.5
)
# 5. 训练模型记录每个 iteration 的损失
def train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs):model.train() # 设置为训练模式# 记录每个 iteration 的损失all_iter_losses [] # 存储所有 batch 的损失iter_indices [] # 存储 iteration 序号# 记录每个 epoch 的准确率和损失train_acc_history []test_acc_history []train_loss_history []test_loss_history []# 早停相关参数best_test_acc 0.0patience 5 # 早停耐心值5个epochcounter 0 # 计数器记录连续未改进的epoch数early_stop False # 早停标志for epoch in range(epochs):running_loss 0.0correct 0total 0for batch_idx, (data, target) in enumerate(train_loader):data, target data.to(device), target.to(device) # 移至GPUoptimizer.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 * 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个批次打印一次训练信息if (batch_idx 1) % 100 0:print(fEpoch: {epoch1}/{epochs} | Batch: {batch_idx1}/{len(train_loader)} f| 单Batch损失: {iter_loss:.4f} | 累计平均损失: {running_loss/(batch_idx1):.4f})# 计算当前epoch的平均训练损失和准确率epoch_train_loss running_loss / len(train_loader)epoch_train_acc 100. * correct / totaltrain_acc_history.append(epoch_train_acc)train_loss_history.append(epoch_train_loss)# 测试阶段model.eval() # 设置为评估模式test_loss 0correct_test 0total_test 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_acc_history.append(epoch_test_acc)test_loss_history.append(epoch_test_loss)# 更新学习率调度器scheduler.step(epoch_test_loss)print(fEpoch {epoch1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%)# 早停检查if epoch_test_acc best_test_acc:best_test_acc epoch_test_acccounter 0# 保存最佳模型可选torch.save(model.state_dict(), best_model.pth)print(f找到更好的模型准确率: {best_test_acc:.2f}%已保存)else:counter 1print(f早停计数器: {counter}/{patience})if counter patience:print(f早停触发连续 {patience} 个epoch测试准确率未提高)early_stop True# 如果触发早停跳出训练循环if early_stop:print(f训练在第 {epoch1} 个epoch提前结束)break# 绘制所有 iteration 的损失曲线plot_iter_losses(all_iter_losses, iter_indices)# 绘制每个 epoch 的准确率和损失曲线plot_epoch_metrics(train_acc_history, test_acc_history, train_loss_history, test_loss_history)return epoch_test_acc # 返回最终测试准确率# 6. 绘制每个 iteration 的损失曲线
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()# 7. 绘制每个 epoch 的准确率和损失曲线
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()# 8. 执行训练和测试
epochs 40 # 增加训练轮次以获得更好效果
print(开始使用CNN训练模型...)
final_accuracy train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs)
print(f训练完成最终测试准确率: {final_accuracy:.2f}%)# # 保存模型
# torch.save(model.state_dict(), cifar10_cnn_model.pth)
# print(模型已保存为: cifar10_cnn_model.pth) 训练完成最终测试准确率: 87.04%
浙大疏精行