网站开发 强制兼容模式,台州网站设计,中国100强企业名单公布,网页顶部导航栏浙大疏锦行 DAY 52 神经网络调参指南 知识点回顾#xff1a; 1. 随机种子 2. 内参的初始化 3. 神经网络调参指南 a. 参数的分类 b. 调参的顺序 c. 各部分参数的调整心得 作业#xff1a;对于day41的简单cnn#xff0c;看看是否可以借助调参指南进一步提高精度。 impor…浙大疏锦行 DAY 52 神经网络调参指南 知识点回顾 1. 随机种子 2. 内参的初始化 3. 神经网络调参指南 a. 参数的分类 b. 调参的顺序 c. 各部分参数的调整心得 作业对于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# 设置中文字体支持
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 128
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__() # 继承父类初始化# ---------------------- 第一个卷积块 ----------------------# 卷积层1输入3通道RGB输出32个特征图卷积核3x3边缘填充1像素self.conv1 nn.Conv2d(in_channels3, # 输入通道数图像的RGB通道out_channels32, # 输出通道数生成32个新特征图kernel_size3, # 卷积核尺寸3x3像素padding1 # 边缘填充1像素保持输出尺寸与输入相同)# 批量归一化层对32个输出通道进行归一化加速训练self.bn1 nn.BatchNorm2d(num_features32)# Softmax激活函数引入非线性公式max(0, x)self.softmax1 nn.Softmax()# 最大池化层窗口2x2步长2特征图尺寸减半32x32→16x16self.pool1 nn.MaxPool2d(kernel_size2, stride2) # stride默认等于kernel_size# ---------------------- 第二个卷积块 ----------------------# 卷积层2输入32通道来自conv1的输出输出64通道self.conv2 nn.Conv2d(in_channels32, # 输入通道数前一层的输出通道数out_channels64, # 输出通道数特征图数量翻倍kernel_size3, # 卷积核尺寸不变padding1 # 保持尺寸16x16→16x16卷积后→8x8池化后)self.bn2 nn.BatchNorm2d(num_features64)self.softmax2 nn.Softmax()self.pool2 nn.MaxPool2d(kernel_size2) # 尺寸减半16x16→8x8# ---------------------- 第三个卷积块 ----------------------# 卷积层3输入64通道输出128通道self.conv3 nn.Conv2d(in_channels64, # 输入通道数前一层的输出通道数out_channels128, # 输出通道数特征图数量再次翻倍kernel_size3,padding1 # 保持尺寸8x8→8x8卷积后→4x4池化后)self.bn3 nn.BatchNorm2d(num_features128)self.softmax3 nn.Softmax() # 复用激活函数对象节省内存self.pool3 nn.MaxPool2d(kernel_size2) # 尺寸减半8x8→4x4# ---------------------- 全连接层分类器 ----------------------# 计算展平后的特征维度128通道 × 4x4尺寸 128×162048维self.fc1 nn.Linear(in_features128 * 4 * 4, # 输入维度卷积层输出的特征数out_features512 # 输出维度隐藏层神经元数)# Dropout层训练时随机丢弃50%神经元防止过拟合self.dropout nn.Dropout(p0.5)# 输出层将512维特征映射到10个类别CIFAR-10的类别数self.fc2 nn.Linear(in_features512, out_features10)def forward(self, x):# 输入尺寸[batch_size, 3, 32, 32]batch_size批量大小3通道数32x32图像尺寸# ---------- 卷积块1处理 ----------x self.conv1(x) # 卷积后尺寸[batch_size, 32, 32, 32]padding1保持尺寸x self.bn1(x) # 批量归一化不改变尺寸x self.softmax1(x) # 激活函数不改变尺寸x self.pool1(x) # 池化后尺寸[batch_size, 32, 16, 16]32→16是因为池化窗口2x2# ---------- 卷积块2处理 ----------x self.conv2(x) # 卷积后尺寸[batch_size, 64, 16, 16]padding1保持尺寸x self.bn2(x)x self.softmax2(x)x self.pool2(x) # 池化后尺寸[batch_size, 64, 8, 8]# ---------- 卷积块3处理 ----------x self.conv3(x) # 卷积后尺寸[batch_size, 128, 8, 8]padding1保持尺寸x self.bn3(x)x self.softmax3(x)x self.pool3(x) # 池化后尺寸[batch_size, 128, 4, 4]# ---------- 展平与全连接层 ----------# 将多维特征图展平为一维向量[batch_size, 128*4*4] [batch_size, 2048]x x.view(-1, 128 * 4 * 4) # -1自动计算批量维度保持批量大小不变x self.fc1(x) # 全连接层2048→512尺寸变为[batch_size, 512]x self.softmax3(x) # 激活函数复用softmax与卷积块3共用x self.dropout(x) # Dropout随机丢弃神经元不改变尺寸x self.fc2(x) # 全连接层512→10尺寸变为[batch_size, 10]未激活直接输出logitsreturn x # 输出未经过Softmax的logits适用于交叉熵损失函数# 初始化模型
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 []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}%)# 绘制所有 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 20 # 增加训练轮次以获得更好效果
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)