公司app与网站建设方案wordpress 增加 专题

当前位置: 首页 > news >正文

公司app与网站建设方案,wordpress 增加 专题,国外包装设计网站大全,做网站和做商城的区别在哪里DAY 52 神经网络调参指南 知识点回顾#xff1a; 1. 随机种子 2. 内参的初始化 3. 神经网络调参指南 a. 参数的分类 b. 调参的顺序 c. 各部分参数的调整心得 作业#xff1a;对于day41的简单cnn#xff0c;看看是否可以借助调参指南进一步提高精度。 随机种子 import…DAY 52 神经网络调参指南 知识点回顾 1.  随机种子 2.  内参的初始化 3.  神经网络调参指南 a.  参数的分类 b.  调参的顺序 c.  各部分参数的调整心得 作业对于day41的简单cnn看看是否可以借助调参指南进一步提高精度。 随机种子 import torch import torch.nn as nn# 定义简单的线性模型无隐藏层

输入2个纬度的数据得到1个纬度的输出

class SimpleNet(nn.Module):def init(self):super(SimpleNet, self).init()# 线性层2个输入特征1个输出特征self.linear nn.Linear(2, 1)def forward(self, x):# 前向传播y w1*x1 w2*x2 breturn self.linear(x)# 创建模型实例 model SimpleNet()# 查看模型参数 print(模型参数:) for name, param in model.named_parameters():print(f{name}: {param.data}) torch中很多场景都会存在随机数

  1. 权重、偏置的随机初始化
  2. 数据加载shuffling打乱与批次加载随机批次加载的随机化
  3. 数据增强的随机化随机旋转、缩放、平移、裁剪等
  4. 随机正则化dropout
  5. 优化器中的随机性 import torch import numpy as np import os import random# 全局随机函数 def set_seed(seed42, deterministicTrue):设置全局随机种子确保实验可重复性参数:seed: 随机种子值默认为42deterministic: 是否启用确定性模式默认为True# 设置Python的随机种子random.seed(seed) os.environ[PYTHONHASHSEED] str(seed) # 确保Python哈希函数的随机性一致比如字典、集合等无序# 设置NumPy的随机种子np.random.seed(seed)# 设置PyTorch的随机种子torch.manual_seed(seed) # 设置CPU上的随机种子torch.cuda.manual_seed(seed) # 设置GPU上的随机种子torch.cuda.manual_seed_all(seed) # 如果使用多GPU# 配置cuDNN以确保结果可重复if deterministic:torch.backends.cudnn.deterministic Truetorch.backends.cudnn.benchmark False# 设置随机种子 set_seed(42) 介绍一下这个随机函数的几个部分
  6. python的随机种子需要确保random模块、以及一些无序数据结构的一致性
  7. numpy的随机种子控制数组的随机性
  8. torch的随机种子控制张量的随机性在cpu和gpu上均适用
  9. cuDNNCUDA Deep Neural Network library CUDA 深度神经网络库的随机性针对cuda的优化算法的随机性 上述种子可以处理大部分场景实际上还有少部分场景具体的函数可能需要自行设置其对应的随机种子。 日常使用中在最开始调用这部分已经足够 内参的初始化 神经网络的权重需要通过反向传播来实现更新那么最开始肯定需要一个值才可以更新参数 这个最开始的值是什么样子的呢如果恰好他们就是那一组最佳的参数附近的数那么可能我训练的速度会快很多 为了搞懂这个问题帮助我们真正理解神经网络参数的本质我们需要深入剖析一下关注以下几个问题
  10. 初始值的区间
  11. 初始值的分布
  12. 初始值是多少 先介绍一下神经网络的对称性—-为什么神经元的初始值需要各不相同 本质神经网络的每一个神经元都是在做一件事输入x–输出y的映射这里我们假设激活函数是sigmoid ysigmoidwxb其中w是连接到该神经元的权重矩阵b是该神经元的偏置 如果所有神经元的权重和偏置都一样
  13. 如果都为0那么所有神经元的输出都一致无法区分不同特征此时反向传播的时候梯度都一样无法学习到特征更新后的权重也完全一致。
  14. 如果不为0同上 所以无论初始值是否为 0相同的权重和偏置会导致神经元在训练过程中始终保持同步。因为神经网络的前向传播是导致权重的数学含义是完全对称的具体表现为 同一层的神经元相当于在做完全相同的计算无论输入如何变化它们的输出模式始终一致。例如输入图像中不同位置的边缘特征会被这些神经元以相同方式处理无法学习到空间分布的差异。 所以需要随机初始化让初始的神经元各不相同。即使初始差异很小但激活函数的非线性梯度不同会放大这种差异。随着训练进行这种分歧会逐渐扩大最终形成功能各异的神经元。 所以明白了上述思想你就知道初始值之前的差异并不需要巨大。 事实上神经网络的初始权重通常设置在接近 0 的小范围内如 [-0.1, 0.1] 或 [-0.01, 0.01]或通过特定分布如正态分布、均匀分布生成小值有很多好处 避免梯度消失 / 爆炸 以 sigmoid 激活函数为例其导数在输入绝对值较大时趋近于 0如 | x|5 时导数≈0。若初始权重过大输入 xw・inputb 可能导致激活函数进入 “饱和区”反向传播时梯度接近 0权重更新缓慢梯度消失。 类比若初始权重是 “大值”相当于让神经元一开始就进入 “极端状态”失去对输入变化的敏感度。 如果梯度相对较大就可以让变化处于sigmoid函数的非饱和区 所以其实对于不同的激活函数 都有对应的饱和区和非饱和区深层网络中饱和区会使梯度在反向传播时逐层衰减底层参数几乎无法更新 注意下这里是wx后才会经过激活函数是多个权重印象的结果不是收到单个权重决定的所以单个权重可以取负数但是如果求和后仍然小于0那么输出会为0 所以初始值一般不会太大结合不同激活函数的特性而且初始值一般是小的值。最终训练完毕可能就会出现大的差异这样最开始让每个参数都是有用的至于最后是不是某些参数归0失去价值那得看训练才知道。 我们来观察下pytorch默认初始化的权重 import torch import torch.nn as nn import matplotlib.pyplot as plt import numpy as np# 设置设备 device torch.device(cuda:0 if torch.cuda.is_available() else cpu)# 定义极简CNN模型仅1个卷积层1个全连接层 class SimpleCNN(nn.Module):def init(self):super(SimpleCNN, self).init()# 卷积层输入3通道输出16通道卷积核3x3self.conv1 nn.Conv2d(3, 16, kernel_size3, padding1)# 池化层2x2窗口尺寸减半self.pool nn.MaxPool2d(kernel_size2)# 全连接层展平后连接到10个输出对应10个类别# 输入尺寸16通道 × 16x16特征图 16×16×164096self.fc nn.Linear(16 * 16 * 16, 10)def forward(self, x):# 卷积池化x self.pool(self.conv1(x)) # 输出尺寸: [batch, 16, 16, 16]# 展平x x.view(-1, 16 * 16 * 16) # 展平为: [batch, 4096]# 全连接x self.fc(x) # 输出尺寸: [batch, 10]return x# 初始化模型 model SimpleCNN() model model.to(device)# 查看模型结构 print(model)# 查看初始权重统计信息 def print_weight_stats(model):# 卷积层conv_weights model.conv1.weight.dataprint(\n卷积层 权重统计:)print(f 均值: {conv_weights.mean().item():.6f})print(f 标准差: {conv_weights.std().item():.6f})print(f 理论标准差 (Kaiming): {np.sqrt(23):.6f}) # 输入通道数为3# 全连接层fc_weights model.fc.weight.dataprint(\n全连接层 权重统计:)print(f 均值: {fc_weights.mean().item():.6f})print(f 标准差: {fc_weights.std().item():.6f})print(f 理论标准差 (Kaiming): {np.sqrt(2/(16*16*16)):.6f})# 改进的可视化权重分布函数 def visualize_weights(model, layer_name, weights, save_pathNone):plt.figure(figsize(12, 5))# 权重直方图plt.subplot(1, 2, 1)plt.hist(weights.cpu().numpy().flatten(), bins50)plt.title(f{layer_name} 权重分布)plt.xlabel(权重值)plt.ylabel(频次)# 权重热图plt.subplot(1, 2, 2)if len(weights.shape) 4: # 卷积层权重 [out_channels, in_channels, kernel_size, kernel_size]# 只显示第一个输入通道的前10个滤波器w weights[:10, 0].cpu().numpy()plt.imshow(w.reshape(-1, weights.shape[2]), cmapviridis)else: # 全连接层权重 [out_features, in_features]# 只显示前10个神经元的权重重塑为更合理的矩形w weights[:10].cpu().numpy()# 计算更合理的二维形状尝试接近正方形n_features w.shape[1]side_length int(np.sqrt(n_features))# 如果不能完美整除添加零填充使能重塑if n_features % side_length ! 0:new_size (side_length 1) * side_lengthw_padded np.zeros((w.shape[0], new_size))w_padded[:, :n_features] ww w_padded# 重塑并显示plt.imshow(w.reshape(w.shape[0] * side_length, -1), cmapviridis)plt.colorbar()plt.title(f{layer_name} 权重热图)plt.tight_layout()if save_path:plt.savefig(f{savepath}{layer_name}.png)plt.show()# 打印权重统计 print_weight_stats(model)# 可视化各层权重 visualize_weights(model, Conv1, model.conv1.weight.data, initial_weights) visualize_weights(model, FC, model.fc.weight.data, initial_weights)# 可视化偏置 plt.figure(figsize(12, 5))# 卷积层偏置 conv_bias model.conv1.bias.data plt.subplot(1, 2, 1) plt.bar(range(len(conv_bias)), conv_bias.cpu().numpy()) plt.title(卷积层 偏置)# 全连接层偏置 fc_bias model.fc.bias.data plt.subplot(1, 2, 2) plt.bar(range(len(fc_bias)), fc_bias.cpu().numpy()) plt.title(全连接层 偏置)plt.tight_layout() plt.savefig(biases_initial.png) plt.show()print(\n偏置统计:) print(f卷积层偏置 均值: {conv_bias.mean().item():.6f}) print(f卷积层偏置 标准差: {conv_bias.std().item():.6f}) print(f全连接层偏置 均值: {fc_bias.mean().item():.6f}) print(f全连接层偏置 标准差: {fc_bias.std().item():.6f})那我们监控权重图的目的是什么呢 训练时权重会随反向传播迭代更新。通过权重分布图能直观看到其从初始化如随机分布到逐渐收敛、形成规律模式的动态变化理解模型如何一步步 “学习” 特征 。比如卷积层权重初期杂乱训练后可能聚焦于边缘、纹理等特定模式。 识别梯度异常
  15. 梯度消失若权重分布越来越集中在 0 附近且更新幅度极小可能是梯度消失模型难学到有效特征比如深层网络用 Sigmoid 激活易出现 。
  16. 梯度爆炸权重值突然大幅震荡、超出合理范围比如从 [-0.1, 0.1] 跳到 [-10, 10] 要警惕梯度爆炸可能让训练崩溃。 借助tensorboard可以看到训练过程中权重图的变化 神经网络调参指南 大部分时候由于光是固定超参数的情况下训练完模型就已经很耗时了所以正常而言基本不会采用传统机器学习的那些超参数方法。 工业界卡特别多的情况下可能可以考虑尤其是在探究一个新架构的时候我们直接忽视这些即可只有手动调参这一条路。 参数的分类 之前我们介绍过了参数 外参实例化的手动指定的 内参其中我们把外参定义为超参数也就是不需要数据驱动的那些参数。 通常可以将超参数分为三类网络参数、优化参数、正则化参数。 网络参数包括网络层之间的交互方式如相加、相乘或串接、卷积核的数量和尺寸、网络层数深度和激活函数等。优化参数一般指学习率、批样本数量、不同优化器的参数及部分损失函数的可调参数。正则化参数如权重衰减系数、丢弃比率dropout。 超参数调优的目的是优化模型找到最优解与正则项之间的关系。网络模型优化的目的是找到全局最优解或相对更好的局部最优解而正则项则希望模型能更好地拟合到最优。两者虽然存在一定对立但目标是一致的即最小化期望风险。模型优化希望最小化经验风险但容易过拟合而正则项用来约束模型复杂度。因此如何平衡两者关系得到最优或较优的解就是超参数调整的目标。 调参顺序 调参遵循 “先保证模型能训练基础配置→ 再提升性能核心参数→ 最后抑制过拟合正则化” 的思路类似 “先建框架再装修最后修细节”。 之前的主要都是停留在第一步先跑起来如果想要更进一步提高精度才是这些调参指南。所以下面顺序建立在已经跑通了的基础上。
  17. 参数初始化—-有预训练的参数直接起飞
  18. batchsize—测试下能允许的最高值
  19. epoch—这个不必多说默认都是训练到收敛位置可以采取早停策略
  20. 学习率与调度器—-收益最高因为鞍点太多了模型越复杂鞍点越多
  21. 模型结构—-消融实验或者对照试验
  22. 损失函数—选择比较少试出来一个即可高手可以自己构建
  23. 激活函数—选择同样较少
  24. 正则化参数—主要是droupout等到过拟合了用上述所有步骤都为了让模型过拟合 这个调参顺序并不固定而且也不是按照重要度来选择是按照方便程度来选择比如选择少的选完后会减小后续实验的成本。 初始化参数 预训练参数是最好的参数初始化方法在训练前先找找类似的论文有无预训练参数其次是Xavir尤其是小数据集的场景多找论文找到预训练模型是最好的做法。关于预训练参数我们介绍过了优先动深层的参数因为浅层是通用的其次是学习率要采取分阶段的策略。 如果从0开始训练的话PyTorch 默认用 Kaiming 初始化适配 ReLU或 Xavier 初始化适配 Sigmoid/Tanh。 bitchsize的选择 当Batch Size 太小的时候模型每次更新学到的东西太少了很可能白学了因为缺少全局思维。所以尽可能高一点16的倍数即可越大越好。 学习率调整 学习率就是参数更新的步长LR 过大→不好收敛LR 过小→训练停滞陷入局部最优 一般最开始用adam快速收敛然后sgd收尾一般精度会高一点只能选一个就adam配合调度器使用。比如 CosineAnnealingLR余弦退火调度器、StepLR固定步长衰减调度器比较经典的搭配就是Adam ReduceLROnPlateauSGD CosineAnnealing或者Adam → SGD StepLR。 比如最开始随便选了做了一组后面为了刷精度就可以考虑选择更精细化的策略了 激活函数的选择 视情况选择一般默认relu或者其变体如leaky relu再或者用tanh。只有二分类任务最后的输出层用sigmoid多分类任务用softmax其他全部用relu即可。此外还有特殊场景下的比如GELU适配 Transformer 损失函数的选择 大部分我们目前接触的任务都是单个损失函数构成的正常选即可 分类任务
  25. 交叉熵损失函数Cross-Entropy Loss–多分类场景
  26. 二元交叉熵损失函数Binary Cross-Entropy Loss–二分类场景
  27. Focal Loss—-类别不平衡场景 注意点
  • CrossEntropyLoss内置 Softmax输入应为原始 logits非概率。
  • BCEWithLogitsLoss内置 Sigmoid输入应为原始 logits。
  • 若评价指标为准确率用交叉熵损失若为 F1 分数考虑 Focal Loss 或自定义损失。 回归任务
  1. 均方误差MSE

  2. 绝对误差MAE 这个也要根据场景和数据特点来选不同损失受到异常值的影响程度不同 此外还有一些序列任务的损失、生成任务的损失等等以后再提 后面会遇到一个任务中有多个损失函数构成比如加权成一个大的损失函数就需要注意到二者的权重配比还有数量级的差异。 模型架构中的参数 比如卷积核尺寸等一般就是7*7、5*5、3*3这种奇数对构成最开始不要用太过分的下采样即可。 神经元的参数直接用 Kaiming 初始化适配 ReLUPyTorch 默认或 Xavier 初始化适配 Sigmoid/Tanh。 正则化系数 droupout一般控制在0.2-0.5之间这里说一下小技巧先追求过拟合后追求泛化性。也就是说先把模型做到过拟合然后在慢慢增加正则化程度。 正则化中如果train的loss可以很低但是val的loss还是很高则说明泛化能力不强优先让模型过拟合再考虑加大正则化提高泛化能力可以分模块来droupout可以确定具体是那部分参数导致过拟合这里还有个小trick是引入残差链接后再利用droupout L2权重衰减这个在优化器中就有这里提一下也可以算是正则化吧。 作业 对于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# 设置中文字体支持 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 64 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)# ReLU激活函数引入非线性公式max(0, x)self.relu1 nn.ReLU()# 最大池化层窗口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.relu2 nn.ReLU()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.relu3 nn.ReLU() # 复用激活函数对象节省内存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.relu1(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.relu2(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.relu3(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.relu3(x) # 激活函数复用relu3与卷积块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 iterloss, 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)testloss 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) 训练完成最终测试准确率: 80.98% 今日调参后的代码

    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 import random import os# 设置中文字体支持 plt.rcParams[font.family] [SimHei] plt.rcParams[axes.unicode_minus] False # 解决负号显示问题# 1. 设置全局随机种子新增 def set_seed(seed42, deterministicTrue):设置全局随机种子确保实验可重复性random.seed(seed)os.environ[PYTHONHASHSEED] str(seed)np.random.seed(seed)torch.manual_seed(seed)torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)if deterministic:torch.backends.cudnn.deterministic Truetorch.backends.cudnn.benchmark False set_seed(42) # 设置随机种子# 检查GPU是否可用 device torch.device(cuda if torch.cuda.is_available() else cpu) print(f使用设备: {device})

    2. 数据预处理优化数据增强

    train_transform transforms.Compose([transforms.RandomCrop(32, padding4),transforms.RandomHorizontalFlip(),transforms.ColorJitter(brightness0.3, contrast0.3, saturation0.3, hue0.15), # 增强抖动幅度transforms.RandomRotation(20), # 增加旋转角度transforms.RandomAffine(degrees0, translate(0.1, 0.1), scale(0.9, 1.1)), # 新增随机平移和缩放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)) ])# 3. 加载CIFAR-10数据集 train_dataset datasets.CIFAR10(root./data,trainTrue,downloadTrue,transformtrain_transform )test_dataset datasets.CIFAR10(root./data,trainFalse,transformtest_transform )# 4. 创建数据加载器增大Batch Size batch_size 128 # 从64增大到128提高训练效率 train_loader DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue) test_loader DataLoader(test_dataset, batch_sizebatch_size, shuffleFalse)

    5. 定义CNN模型修改初始化方式

    class CNN(nn.Module):def init(self):super(CNN, self).init()# 第一个卷积块self.conv1 nn.Conv2d(3, 32, kernel_size3, padding1)self.bn1 nn.BatchNorm2d(32)self.relu1 nn.ReLU()self.pool1 nn.MaxPool2d(2)# 第二个卷积块self.conv2 nn.Conv2d(32, 64, kernel_size3, padding1)self.bn2 nn.BatchNorm2d(64)self.relu2 nn.ReLU()self.pool2 nn.MaxPool2d(2)# 第三个卷积块self.conv3 nn.Conv2d(64, 128, kernel_size3, padding1)self.bn3 nn.BatchNorm2d(128)self.relu3 nn.ReLU()self.pool3 nn.MaxPool2d(2)# 全连接层self.fc1 nn.Linear(128 * 4 * 4, 512)self.dropout nn.Dropout(p0.3) # 新增Dropout从0.5降低到0.3过拟合时可增大self.fc2 nn.Linear(512, 10)# 自定义初始化替换PyTorch默认初始化self._initialize_weights()def _initialize_weights(self):使用Kaiming初始化卷积层Xavier初始化全连接层for m in self.modules():if isinstance(m, nn.Conv2d):nn.init.kaimingnormal(m.weight, modefanout, nonlinearityrelu)if m.bias is not None:nn.init.constant(m.bias, 0)elif isinstance(m, nn.BatchNorm2d):nn.init.constant(m.weight, 1)nn.init.constant(m.bias, 0)elif isinstance(m, nn.Linear):nn.init.xavieruniform(m.weight)nn.init.constant_(m.bias, 0)def forward(self, x):x self.conv1(x)x self.bn1(x)x self.relu1(x)x self.pool1(x)x self.conv2(x)x self.bn2(x)x self.relu2(x)x self.pool2(x)x self.conv3(x)x self.bn3(x)x self.relu3(x)x self.pool3(x)x x.view(-1, 128 * 4 * 4)x self.fc1(x)x self.relu3(x)x self.dropout(x)x self.fc2(x)return x# 初始化模型 model CNN() model model.to(device) criterion nn.CrossEntropyLoss() # 保持交叉熵损失适用于分类任务

    6. 优化器与学习率调度器优化配置

    optimizer optim.Adam(model.parameters(), lr0.001, weight_decay1e-4) # 新增L2正则化weight_decay scheduler optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max30, # 余弦退火周期eta_min1e-5 # 最小学习率 )# 7. 训练模型调整训练策略 def train(model, train_loader, test_loader, criterion, optimizer, scheduler, device, epochs):model.train()all_iter_losses []iter_indices []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)optimizer.zero_grad()output model(data)loss criterion(output, target)loss.backward()optimizer.step()iter_loss loss.item()all_iter_losses.append(iter_loss)iter_indices.append(epoch * len(train_loader) batch_idx 1)running_loss iterloss, predicted output.max(1)total target.size(0)correct predicted.eq(target).sum().item()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_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)testloss 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)# 更新学习率根据调度器类型调整if isinstance(scheduler, optim.lr_scheduler.ReduceLROnPlateau):scheduler.step(epoch_test_loss)else:scheduler.step() # CosineAnnealingLR每epoch更新print(fEpoch {epoch1}/{epochs} 完成 | 训练准确率: {epoch_train_acc:.2f}% | 测试准确率: {epoch_test_acc:.2f}%)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

    8. 绘制损失曲线

    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()# 9. 绘制准确率和损失曲线 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()# 10. 执行训练增加训练轮次 epochs 30 # 从20增加到30给模型更多收敛时间 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_optimized.pth) print(模型已保存为: cifar10_cnn_optimized.pth) 训练完成最终测试准确率: 81.09%   模型已保存为: cifar10_cnn_optimized.pth 浙大疏锦行