GoogLeNet训练CIFAR10[Pytorch+训练信息+.pth文件]

news/2024/12/22 10:29:59/文章来源:https://www.cnblogs.com/hello-nullptr/p/18445622

0 引言

  • GoogLeNet,它是一种深度卷积神经网络,由Google研究人员在2014年提出,用于图像识别任务。
  • CIFAR-10是一个常用的图像识别数据集,包含10个类别,每个类别有6000张32x32的彩色图像。
  • 本文使用Pycharm及Pytorch框架搭建GoogLeNet神经网络框架,使用CIFAR10数据集训练模型。
  • 笔者查阅资料时发现绝大多数文章仅仅给出代码而没有训练信息、模型参数文件。在CSDN社区出现收费情况,下载后可能是智商税,笔者认为十分不友好,故写此随笔。

1 GoogLeNet

  • 论文下载网址:Going deeper with convolutions
  • 发表期刊网址:IEEE
  • 网络架构图片:
    image

2 CIFAR-10数据集

  • 数据集网址:CIFAR10

image

CIFAR-10数据集由10个类别的60000张32x32彩色图像组成,每个类别有6000张图像。有50000个训练图像和10000个测试图像。数据集分为五个训练批次和一个测试批次,每个批次有10000张图像。测试批次包含从每个类别中随机选择的1000张图像。训练批包含随机顺序的剩余图像,但某些训练批可能包含来自一个类的图像多于另一个类。在它们之间,训练批次包含来自每个类的5000张图像。[百度翻译]

3 搭建GoogLeNet网络框架

点击查看GoogLeNet.py
import torch
from torch import nnclass Inception(nn.Module):# type [batch channel height width]def __init__(self,cov_in,p1_1_cov_oc,p2_1_cov_oc,p2_2_cov_oc,p3_1_cov_oc,p3_2_cov_oc,p4_2_cov_oc):super(Inception, self).__init__()self.path1=nn.Sequential(# in [1,cov_in,224,224]nn.Conv2d(in_channels=cov_in, out_channels=p1_1_cov_oc, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(p1_1_cov_oc),nn.ReLU(inplace=True)# out [1,p1_1_cov_oc,224,224])self.path2 = nn.Sequential(# in [1,cov_in,224,224]nn.Conv2d(in_channels=cov_in, out_channels=p2_1_cov_oc, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(p2_1_cov_oc),nn.ReLU(inplace=True),# out [1,p2_1_cov_oc,224,224]# in [1,p2_1_cov_oc,224,224]nn.Conv2d(in_channels=p2_1_cov_oc, out_channels=p2_2_cov_oc, kernel_size=3, stride=1, padding=1),nn.BatchNorm2d(p2_2_cov_oc),nn.ReLU(inplace=True)# out [1,p2_2_cov_oc,224,224])self.path3 = nn.Sequential(# in [1,cov_in,224,224]nn.Conv2d(in_channels=cov_in, out_channels=p3_1_cov_oc, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(p3_1_cov_oc),nn.ReLU(inplace=True),# out [1,p3_1_cov_oc,224,224]# in [1,p3_1_cov_oc,224,224]nn.Conv2d(in_channels=p3_1_cov_oc, out_channels=p3_2_cov_oc, kernel_size=5, stride=1, padding=2),nn.BatchNorm2d(p3_2_cov_oc),nn.ReLU(inplace=True)# out [1,p3_2_cov_oc,224,224])self.path4 = nn.Sequential(# in [1,cov_in,224,224]nn.MaxPool2d(kernel_size=3,stride=1,padding=1),# out [1,cov_in,224,224]# in [1,cov_in,224,224]nn.Conv2d(in_channels=cov_in, out_channels=p4_2_cov_oc, kernel_size=1, stride=1, padding=0),nn.BatchNorm2d(p4_2_cov_oc),nn.ReLU(inplace=True)# out [1,p4_2_cov_oc,224,224])def forward(self,x):p1=self.path1(x)p2=self.path2(x)p3=self.path3(x)p4=self.path4(x)r1=torch.cat(tensors=[p1,p2,p3,p4],dim=1)return r1class GoogLeNet(nn.Module):def __init__(self):super(GoogLeNet, self).__init__()#type [batch channel height width]self.block1=nn.Sequential(#in [3,32,32]nn.Conv2d(in_channels=3,out_channels=192,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(192),nn.ReLU(inplace=True),# out [192,32,32]# in [192,32,32]nn.MaxPool2d(kernel_size=3,stride=1,padding=1),# out [192,32,32])self.block2=nn.Sequential(# in [192,32,32]Inception(192,64,96,128,16,32,32),# out [256,32,32]# in [256,32,32]Inception(256,128,128,192,32,96,64),# out [480,32,32]# in [480,32,32]nn.MaxPool2d(kernel_size=3,stride=2,padding=1)# out [480,16,16])self.block3 = nn.Sequential(# in [480,16,16]Inception(480,192,96,208,16,48,64),# out [512,16,16]# in [512,16,16]Inception(512,160,112,224,24,64,64),# out [512,16,16]# in [512,16,16]Inception(512,128,128,256,24,64,64),# out [512,16,16]# in [512,16,16]Inception(512,112,128,288,32,64,64),# out [528,16,16]# in [528,16,16]Inception(528,256,160,320,32,128,128),# out [832,16,16]# in [832,16,16]nn.MaxPool2d(kernel_size=3, stride=2, padding=1)# out [832,8,8])self.block4 = nn.Sequential(# in [832,8,8]Inception(832,256,160,320,32,128,128),# out [832,8,8]# in [832,8,8]Inception(832,384,192,384,48,128,128),# out [1024,8,8]# in [1024,8,8]nn.AvgPool2d(kernel_size=8,stride=1,padding=0),# out [1024,1,1])self.block5=nn.Sequential(# in [1024,1,1]nn.Flatten(),# out [1024]# in [1024]nn.Linear(in_features=1024, out_features=10),# out [10]nn.Softmax(dim=0))#模型参数初始化for m in self.modules():if isinstance(m,nn.Conv2d):nn.init.kaiming_normal_(m.weight,mode='fan_out',nonlinearity='relu')if m.bias is not None:nn.init.constant_(m.bias,0)elif isinstance(m,nn.Linear):nn.init.normal_(m.weight,0,0.001)if m.bias is not None:nn.init.constant_(m.bias,0)def forward(self,x):x=self.block1(x)x=self.block2(x)x=self.block3(x)x=self.block4(x)x=self.block5(x)return x
由于GoogLeNet论文的模型训练时间过长,笔者将网络架构稍微进行改动,改动点:
  1. 初始卷积模块进行改动
    image

  2. 删除了辅助分类器(Auxiliary Classifier)
    image

改动后使得每个EPOCH训练耗时300秒左右。

4 主程序

4.1 数据预处理

image
上图为数据预处理的代码,大致操作是将图像转为张量格式再将图像数据进行标准化处理,设置每批次的数据量是40张图像,训练数据集打乱,测试数据集不打乱。

transforms.Normalize是一个预处理步骤,用于对图像数据进行标准化处理。这个步骤通常在图像输入到神经网络之前进行,目的是使得模型训练更加稳定和高效。Normalize的两个参数mean和std分别代表数据的均值和标准差,这两个参数需要提前计算。

  • mean:这是一个长度与图像通道数相同的列表或元组,表示每个通道的均值。例如,对于RGB图像,mean可能是[0.485, 0.456, 0.406],表示红色、绿色和蓝色通道的均值。
  • std:这同样是一个长度与图像通道数相同的列表或元组,表示每个通道的标准差。例如,std可能是[0.229, 0.224, 0.225],表示红色、绿色和蓝色通道的标准差。

4.2 加载模型及初始化

image
上图为加载模型及初始化的代码,大致操作是实例化GoogLeNet模型并设置损失函数、优化器、学习率优化器。损失函数为交叉熵损失,优化器是随机梯度下降,使用余弦退火学习率。

如果你已经有训练好的模型,想要继续训练提升精度,需要使用torch.load加载模型参数文件。

4.3 训练代码

image
上图是训练代码,每训练一批数据(40张图像一次性放入显存)就更新神经网络参数,所有训练集图像(50000张)训练完后输出训练信息及更新学习率,这样一共重复执行EPOCH_CNT次(for循环嵌套)。

4.4 测试代码

image
上图为测试代码,大致操作是将之前训练的模型用测试集(10000张)测试一遍,统计预测正确的占比并输出相关信息,保存模型。

点击查看MAIN.py
import torch
import time
import torchvision
import sys
from tqdm import tqdm, trange
from torch import nn
from torch.utils.data import DataLoader
from torchsummary import summary
from torchvision import transforms
from torch.nn import functional as F
from Package_1.Pytorch.GoogLeNet.CIFAR10.GoogLeNet import GoogLeNetEPOCH_CNT=200
LEARN_RATE=1e-2if __name__ == '__main__':#CIFAR-10 is a subset of the Tiny Images dataset with 60000 32x32 color images of 10 classes#均值:[0.49139968 0.48215841 0.44653091] 标准差:[0.24703223 0.24348513 0.26158784]transform_train=transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.49139968,0.48215841,0.44653091],std=[0.24703223,0.24348513,0.26158784]),])transform_test=transforms.Compose([transforms.ToTensor(),transforms.Normalize(mean=[0.49139968,0.48215841,0.44653091],std=[0.24703223,0.24348513,0.26158784]),])data_train=torchvision.datasets.CIFAR10(root="../../dataset/dataset_CIFAR10",train=True,download=False,transform=transform_train)data_test=torchvision.datasets.CIFAR10(root="../../dataset/dataset_CIFAR10",train=False,download=False,transform=transform_test)loader_train=DataLoader(dataset=data_train,batch_size=40,shuffle=True,drop_last=False)loader_test=DataLoader(dataset=data_test,batch_size=40,shuffle=False,drop_last=False)#损失函数model=GoogLeNet().cuda()lossfun_cross=nn.CrossEntropyLoss().cuda()optimer=torch.optim.SGD(model.parameters(),lr=LEARN_RATE,momentum=0.9, weight_decay=1e-6,nesterov=True)scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimer,T_max=EPOCH_CNT)#训练for iEpoch in range(0,EPOCH_CNT,1):#重复EPOCH_CNT次tm_start = time.time()model.train()accurate_train=0f_loss_total_train=0.0for img,label in tqdm(loader_train,desc='train'):img=img.cuda()label=label.cuda()img1=model(img)ret_loss=lossfun_cross(img1,label)f_loss_total_train+=float(ret_loss)accurate_train += (torch.argmax(input=img1, dim=1) == label).sum()optimer.zero_grad()ret_loss.backward()optimer.step()print("epoch={} lr={:.6f} Train-Avg-Loss={:.3f} 训练集准确率={:.3f}%".format(iEpoch,scheduler.get_last_lr()[0],f_loss_total_train/len(loader_train),accurate_train/len(data_train)*100),end=" ")scheduler.step()model.eval()accurate_test=0f_loss_total_test=0.0with torch.no_grad():for img,label in loader_test:img = img.cuda()label = label.cuda()img1=model(img)ret_loss=lossfun_cross(img1,label)f_loss_total_test+=float(ret_loss)accurate_test+=(torch.argmax(input=img1,dim=1)==label).sum()#保存模型torch.save(model,"./GoogLeNet_CIFAR10_epoch_{:d}_acc_{:.3f}_.pth".format(iEpoch,accurate_test/len(data_test)*100))tm_end = time.time()print("Test-Avg-Loss={:.3f} 验证集准确率={:.3f}% 共耗时={:.3f}s".format(f_loss_total_test/len(loader_test),accurate_test/len(data_test)*100,tm_end-tm_start))

5 训练模型

5.1 设定参数

训练过程中的参数设置:
批量大小:40,每次40张图像一次性放入GPU显存计算
学习率:初始学习率为0.01,根据余弦退火自动调整学习率。
迭代次数:设定为200次,但笔者并没有运行到200。

5.2 学习率曲线

image
笔者在训练期间电脑出现蓝屏、训练中断情况,笔者又加载训练好的模型继续训练,在EPOCH=70和EPOCH=91出现学习率异常。EPOCH=45~53为拟合出来的数据。

5.3 损失曲线

image
由于设备出现问题,EPOCH=45~53数据是笔者拟合出来的替代数据,在后文所给EXCEL文件中已标注。

5.3 准确率曲线

image
准确率值并未丢失(保存的模型命名上含有准确率)。

5.4 耗时曲线

image
EPOCH=45~53数据是笔者拟合出来的替代数据,在后文所给EXCEL文件中已标注。

6 结论

笔者模型训练耗时大概7~8小时,读者可以自行修改训练,例如数据增强、修改网络架构、调整超参数等

附录

完整代码+训练信息+pth模型参数见百度网盘链接:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/807431.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IntelliJ IDEA中,代码折叠(Code Folding)功能 取消 默认的 方法体自动展开

默认情况下 方法体 代码折叠后,再次启动 IDEA 时 会自动展开 取消 下面的多选框 则 下次启动不会自动展开

2024国庆S综合强化Day3

今天的题比较简单。 A link

“订单、账单、支付单”关系解析

当交易、支付等体系糅合在一起时,可能会产生许多单据或单号,这个时候,要怎么理解单据在交易正、逆向中的联系?这篇文章里,作者结合设定场景做了解读,或许可以帮你理解“订单、账单、支付单”关系。有朋友提出一个问题比较典型,可能是很多朋友的疑问点:整个交易、支付、…

闲话 10.2

闲话 10.2 你说得对但我还是想写些废话出来你说的对,以前假期比上不足比下有余,现在没有下了。10.1 上午的唐氏模拟赛,忙活一上午只有 55pts,还因为 T4 freopen 开错了挂 15pts。 T1 感觉哪里很对但很怪,死活调不出来大样例三,于是两个小时就摆了,结果大败而归,事实上…

C++ 容器适配器

除了顺序容器外,标准库还定义了三个顺序容器适配器:stack、queue和priority_queue。适配器(adaptor)是标准库中的一个通用概念****。容器、迭代器和函数都有适配器。本质上,一个适配器是一种机制,能使某种事物的行为看起来像另外一种事物一样。一个容器适配器接受一种已有的…

【HITCON-Training】Lab 14 - MagicHeap

学习于2024-10-03 12:50:42 星期四 心得感想: 分析 ida一打开就看到很明显的提示(毕竟是教学关卡):那么我们需要将magic修改为一个大于0x1305的数,并且该程序没有开PIE,那么magic地址就是固定的。 Delete操作删的非常彻底,很明显这里没有任何可以利用的:Create部分看起…

C++ 额外的 string 操作

string 构造:▲ 《C++ Primer》 P321string 裁剪:▲ 322修改 string 的操作:▲ 《C++ Primer》 P323string 的搜索操作:▲ 《C++ Primer》 P325string 的 compare 函数:▲《C++ Primer》 P327

动静态库

静态库: 文件扩展名:.a 链接方式是在编译时候直接集成到可执行文件中。动态库 文件扩展名字:.so 链接方式是在运行时,根据符号表查找动态库的位置库文件:就是把多个“.o文件”打一个包,给对方提供一个库文件。 使用ar命令生成静态库 ar -rc libmymath.a add.o sub.o交付库…

C++ 顺序容器大小操作 resize

▲ 《C++ Primer》 P314▲ 《C++ Primer》 P318