2025年【深度学习】绘制模型训练曲线(epoch-accuracy),寻找**epoch值

【深度学习】绘制模型训练曲线(epoch-accuracy),寻找**epoch值一 什么是 epoch 在卷积神经网络 CNN 训练中 epoch 周期 是一个重要的概念 表示模型训练过程中数据集的完整遍历次数 通过多次 epoch 模型逐渐适应训练数据 提高性能 并通过验证性能监测模型的泛化能力

大家好,我是讯享网,很高兴认识大家。

一、什么是epoch

在卷积神经网络(CNN)训练中,"epoch"(周期)是一个重要的概念,表示模型训练过程中数据集的完整遍历次数。通过多次"epoch",模型逐渐适应训练数据,提高性能,并通过验证性能监测模型的泛化能力。在深度学习中,正确设置"epoch"的数量是一个重要的超参数,需要根据具体问题和数据集来调整。

Epoch设置过大

  • 过拟合风险:如果 epoch 设置过大,模型有可能过度拟合训练数据,即模型在训练数据上表现得非常好,但在新数据上表现较差。这是因为模型会记住噪声和细节,而不是学习通用规律。
  • 浪费时间和计算资源:较大的 epoch 会占用更多的时间和计算资源,而结果可能不会有显著的提升。这对于大规模深度学习模型来说特别昂贵。

Epoch设置过小

  • 欠拟合风险:如果 epoch 设置得太小,模型可能无法捕获训练数据中的模式和特征,导致训练不足,模型性能较差。
  • 性能下降:模型需要一定的训练时间才能逐渐学习数据的特征。如果 epoch 设置太小,模型可能没有足够的时间来收敛,导致性能下降。

二、绘制epoch-accuracy(准确性)与epoch-loss(损失值)曲线图,寻找**epoch

所用数据文件:点击下载

import torch from torch.utils.data import Dataset, DataLoader import numpy as np from PIL import Image from torchvision import transforms # 定义数据预处理的转换 data_transforms = { 'train': transforms.Compose([ transforms.Resize([256,256]), transforms.ToTensor() ]), 'valid': transforms.Compose([ transforms.Resize([256, 256]), transforms.ToTensor() ]), } # 定义自定义的数据集类 class food_dataset(Dataset): # food_dataset是自己创建的类名称,可以改为你需要的名称 def __init__(self, file_path, transform=None): # 类的初始化 self.file_path = file_path self.imgs = [] self.labels = [] self.transform = transform with open(self.file_path) as f: samples = [x.strip().split(' ') for x in f.readlines()] for img_path, label in samples: self.imgs.append(img_path) self.labels.append(label) def __len__(self): # 类实例化对象后,可以使用len函数测量对象的个数 return len(self.imgs) def __getitem__(self, idx): # 关键,可通过索引的形式获取每一个图片数据及标签 image = Image.open(self.imgs[idx]) # if self.transform: image = self.transform(image) label = self.labels[idx] label = torch.from_numpy(np.array(label, dtype=np.int64)) return image, label # 创建训练集和测试集的实例 training_data = food_dataset(file_path='./train.txt', transform=data_transforms['train']) test_data = food_dataset(file_path='./test.txt', transform=data_transforms['valid']) # 创建训练集和测试集的数据加载器 train_dataloader = DataLoader(training_data, batch_size=64, shuffle=True) # 64张图片为一个包, test_dataloader = DataLoader(test_data, batch_size=64, shuffle=True) '''-------------cnn卷积神经网络部分----------------------''' #此行根据支持 CUDA 的 GPU 和 MPS 的可用性设置变量。 # 它使用 检查启用了 CUDA 的 GPU 是否可用。如果为 true,则设置为“cuda”。 # 否则,它将使用 检查 MPS 是否可用。如果为 true,则设置为“mps”。如果两个条件都为 false,则设置为“cpu”。 device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu" print(f"Using {device} device") ''' 定义神经网络 ''' from torch import nn class CNN(nn.Module): def __init__(self): # 输入大小 (3, 256, 256) super(CNN, self).__init__() self.conv1 = nn.Sequential( # 将多个层组合成一起。 nn.Conv2d( # 2d一般用于图像,3d用于视频数据(多一个时间维度),1d一般用于结构化的序列数据 in_channels=3, # 图像通道个数,1表示灰度图(确定了卷积核 组中的个数), out_channels=16, # 要得到几多少个特征图,卷积核的个数 kernel_size=5, # 卷积核大小,5*5 stride=1, # 步长 padding=2, # 一般希望卷积核处理后的结果大小与处理前的数据大小相同,效果会比较好。那padding改如何设计呢?建议stride为1,kernel_size = 2*padding+1 ), # 输出的特征图为 (16, 256, 256) nn.ReLU(), # relu层 nn.MaxPool2d(kernel_size=2), # 进行池化操作(2x2 区域), 输出结果为: (16, 128, 128) ) self.conv2 = nn.Sequential( # 输入 (16, 128, 128) nn.Conv2d(16, 32, 5, 1, 2), # 输出 (32, 128, 128) nn.ReLU(), # relu层 nn.Conv2d(32, 32, 5, 1, 2), # 输出 (32, 128, 128) nn.ReLU(), nn.MaxPool2d(2), # 输出 (32, 64, 64) ) self.conv3 = nn.Sequential( # 输入 (32, 64, 64) nn.Conv2d(32, 64, 5, 1, 2), nn.ReLU(), # 输出 (64, 64, 64) ) self.out = nn.Linear(64 * 64 * 64, 20) # 全连接层得到的结果 def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) # 输出 (64,64, 32, 32) x = x.view(x.size(0), -1) # flatten操作,结果为:(batch_size, 64 * 32 * 32) output = self.out(x) return output model = CNN().to(device) def train(dataloader, model, loss_fn, optimizer): model.train() # pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。 # 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。 for X, y in dataloader: # 其中batch为每一个数据的编号 X, y = X.to(device), y.to(device) # 把训练数据集和标签传入cpu或GPU pred = model.forward(X) # 自动初始化 w权值 loss = loss_fn(pred, y) # 通过交叉熵损失函数计算损失值loss # Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络 optimizer.zero_grad() # 梯度值清零 loss.backward() # 反向传播计算得到每个参数的梯度值 optimizer.step() # 根据梯度更新网络参数 def test(dataloader,model,loss_fn): size= len (dataloader.dataset) #计算测试数据集的总样本数。 num_batches = len(dataloader) #计算测试数据集的总样本数。 model.eval()#通过这个方法将神经网络模型设置为评估模式,以关闭一些在训练时启用的操作,例如丢弃。 test_loss,correct=0,0 #初始化两个变量 test_loss 和 correct,分别用于累积测试损失和正确分类的样本数量。 with torch.no_grad(): #使用 torch.no_grad() 上下文管理器,将其包裹的代码块中的梯度计算禁用,以减少内存使用和加速计算。 for X,y in dataloader: #开始遍历测试数据加载器中的每个批次,每个批次包括输入数据 X 和相应的标签 y。 X,y=X.to(device),y.to(device) #将测试数据移动到指定的设备,以确保与模型的设备匹配。 pred=model.forward(X) #使用神经网络模型进行前向传播,得到预测结果 pred。 test_loss += loss_fn(pred,y).item() #计算并累积测试损失,通过使用损失函数 loss_fn 计算模型的预测结果 pred 与真实标签 y 之间的损失。 # 计算并累积正确分类的样本数量。这里使用了 argmax 函数来找到预测结果中的最大值对应的类别,然后检查是否与真实标签匹配,并将匹配的结果转换为浮点数。 correct += (pred.argmax(1)==y).type(torch.float).sum().item() a = (pred.argmax(1) == y) # dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号 b = (pred.argmax(1) == y).type(torch.float) test_loss /=num_batches #计算测试的平均损失,将累积的损失值除以批次数目。 correct /= size #计算准确率,将正确分类的样本数量除以总样本数,然后将其乘以 100 得到百分比形式。 print(f'Test result:\n Accuracy:{(100*correct)}%,Avg loss: {test_loss}') #打印测试结果,包括准确率和平均损失。 acc_s.append(correct) loss_s.append(test_loss) loss_fn = nn.CrossEntropyLoss() # 创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果 optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 创建一个优化器,SGD为随机梯度下降算法?? '''训练模型''' epochs = 50 # 训练次数 acc_s = [] # 存储每个 epoch 的准确率 loss_s = [] # 存储每个 epoch 的损失值 for t in range(epochs): print(f"Epoch {t + 1}\n-------------------------------") # 训练模型 train(train_dataloader, model, loss_fn, optimizer) # 在测试集上评估模型 test(test_dataloader, model, loss_fn) '''绘制训练效果曲线''' from matplotlib import pyplot as plt # 创建子图,分别用于绘制准确率和损失值 plt.subplot(1, 2, 1) plt.plot(range(0, epochs), acc_s) plt.xlabel('epoch') plt.ylabel('accuracy') plt.subplot(1, 2, 2) plt.plot(range(0, epochs), loss_s) plt.xlabel('epoch') plt.ylabel('loss') plt.show() # 显示绘制的图形 print("Done!") # 训练结束 

讯享网

三、运行结果及分析

1、epoch=20:


讯享网

2、epoch=20(添加数据增强):(后面的都是添加数据增强后的)

注意数据增强详见:数据增强的原理及实现(超详细)

3、epoch=50:

4、epoch=100:

5、epoch=150:

 综上所述:基本上可以确定epoch的值在 60~80 为**!

小讯
上一篇 2025-03-21 17:55
下一篇 2025-01-10 12:20

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/19841.html