Pytorch-第八回卷积神经网络GoogleNet模型
Pytorch 第八回:卷积神经网络——GoogleNet模型
Pytorch 第八回:卷积神经网络——GoogleNet模型
本次开启深度学习第八回,基于Pytorch的GoogleNet卷积神经网络模型。对于卷积神经网络,咱们讲过了AlexNe模型和VGG模型。本回再分享一个新的模型,叫做GoogleNet模型。这个模型的突出点是采用了不同大小的卷积核进行组合训练。接下来给大家分享具体思路。 本次学习,借助的平台是PyCharm 2024.1.3,python版本3.11 numpy版本是1.26.4,pytorch版本2.0.0+cu118
前言
讲解模型前,先分享几个概念,统一下思想:
1、GoogleNet模型
2014年的ImageNet大规模视觉竞赛中,出彩的不止有VGG模型,还有GoogleNet模型。GoogleNet模型在当年是夺得了比赛的冠军,VGG模型夺得了亚军。GoogLeNet模型,在不大量增加硬件计算力的前提下,采用提高网络模型深度和宽度的方法,提高了模型的准确率。其中,GooogleNet模型的核心结构是Inception块。Inception块架构如下图所示:
2、inception块
如上图所示,inception块有四条路径并联组成。左一路径有一层卷积;左二路径有两层不同卷积核的卷积层;右二路径有两层不同卷积核的卷积;右一路径有一层卷积和一层池化。具体代码可以继续看下文。 该结构的成功,表明不同尺寸的滤波器可以有效识别不同范围的图像细节。那这个块有可改变的的变量吗?肯定有,它的超参数是每层输入和输出的通道数。 注: 在机器学习中,超参数是模型训练过程的配置变量。
3、批量规范化
通过批量规范化,可以帮助深层神经网络在短时间进行收敛。
其公式如下:
其中,x为小批量的输入,u’为小批量样本的均值,p’为小批量样本的标准差。应用标准化后,生成的小批量的均值为0,单位方差为1。由于单位方差是人为的影响,因此需要拉伸参数a和偏移参数b进行矫正。同时,参数a和b是需要在模型训练过程中进行学习优化的。
注:
在训练模式下,数据的均值和方差只能通过小批量的方式来获取,而测试模式下,可以根据整个测试集进行精确计算均值和方差。
4、影响神经网络的训练因素有哪些,可以先总结一下:
1)数据预处理的效果; 2)随着神经网络的加深,中间层的变量具有更大的变化范围; 3)网络的层数增多时,其过拟合的几率也在加大。 闲言少叙,直接展示逻辑,先上引用: import numpy as np import torch from torch import nn from torchvision.datasets import CIFAR10 import time from torch.utils.data import DataLoader
一、数据准备
如前几回一样,本次仍然采用CIFAR10数据集,因此不做重点解释(有兴趣的可以查看前两回的内容),本回只展示代码: def data_tf(x): x = x.resize((96, 96), 2) x = np.array(x, dtype=‘float32’) / 255 x = (x - 0.5) / 0.5 x = x.transpose((2, 0, 1)) x = torch.from_numpy(x) return x train_set = CIFAR10(’./data’, train=True, transform=data_tf) train_data = torch.utils.data.DataLoader(train_set, batch_size=64, shuffle=True)
二、模型准备
1.搭建inception块
(展示的代码有点长,大家不要一上来就感到心烦,耐心看一下,还是比较简单。) 如上文所述,inception块是将四个线路的网络合成了一个网络。需要注意的是,这里为了加快数据的收敛,引用了批量标准化。这点可能和原始的inception块结构不一样。 inception块的输入参数由各个路线的通道数量组成,输出为搭建好的inception网络,具体如下: class inception(nn.Module): def init(self, channel_in, channel_out1, channel_out2, channel_out3, channel_out4): super(inception, self).init() channel_out2_1 = channel_out2[0] channel_out2_2 = channel_out2[1] channel_out3_1 = channel_out3[0] channel_out3_2 = channel_out3[1]
第一条线路 1*1卷积
self.path1 = nn.Sequential( nn.Conv2d(channel_in, channel_out1, kernel_size=1, stride=1), nn.BatchNorm2d(channel_out1, eps=1e-3), nn.ReLU(True) )
第二条线路 11卷积-> 33卷积+填充1
self.path2 = nn.Sequential( nn.Conv2d(channel_in, channel_out2_1, kernel_size=1, stride=1), nn.BatchNorm2d(channel_out2_1, eps=1e-3), nn.ReLU(True), nn.Conv2d(channel_out2_1, channel_out2_2, kernel_size=3, stride=1, padding=1), nn.BatchNorm2d(channel_out2_2, eps=1e-3), nn.ReLU(True) )
第三条线路 11卷积-> 55卷积+填充2
self.path3 = nn.Sequential( nn.Conv2d(channel_in, channel_out3_1, kernel_size=1, stride=1), nn.BatchNorm2d(channel_out3_1, eps=1e-3), nn.ReLU(True), nn.Conv2d(channel_out3_1, channel_out3_2, kernel_size=5, stride=1, padding=2), nn.BatchNorm2d(channel_out3_2, eps=1e-3), nn.ReLU(True) )
第四条线路 33池化+填充1-> 33卷积
self.path4 = nn.Sequential( nn.MaxPool2d(3, stride=1, padding=1), nn.Conv2d(channel_in, channel_out4, kernel_size=1, stride=1), nn.BatchNorm2d(channel_out4, eps=1e-3), nn.ReLU(True) ) def forward(self, x): y1 = self.path1(x) y2 = self.path2(x) y3 = self.path3(x) y4 = self.path4(x) output = torch.cat((y1, y2, y3, y4), dim=1) return output
2.GoogleNet网络搭建
GoogleNet模型下有五个网络块,通过使用9个Inception块和池化层的堆叠来完成其数值预测。从代码中可以看出,相比前两回分享的模型,GoogleNet模型的网络是又宽又深。当然,GoogleNet模型主要由卷积层和池化层组成,减少了全连接层,因此其神经元的个数在一定程度上也是优化过的。 GoogleNet模型输入为数据的通道数,输出为分类的类别数目。 class googlenet(nn.Module): def init(self, channel_in, class_out): super(googlenet, self).init()
网络块1
self.block1 = nn.Sequential( nn.Conv2d(channel_in, 64, kernel_size=7, stride=2,padding=3), nn.BatchNorm2d(64, eps=1e-3), nn.ReLU(True), nn.MaxPool2d(3, 2,padding=1))
网络块2
self.block2 = nn.Sequential( nn.Conv2d(64, 64, kernel_size=1), nn.BatchNorm2d(64, eps=1e-3), nn.ReLU(True), nn.Conv2d(64, 192, kernel_size=3, padding=1), nn.BatchNorm2d(192, eps=1e-3), nn.ReLU(True), nn.MaxPool2d(3, 2,padding=1))
网络块3
self.block3 = nn.Sequential( inception(192, 64, (96, 128), (16, 32), 32), inception(256, 128, (128, 192), (32, 96), 64), nn.MaxPool2d(3, 2))
网络块4
self.block4 = nn.Sequential( inception(480, 192, (96, 208), (16, 48), 64), inception(512, 160, (112, 224), (24, 64), 64), inception(512, 128, (128, 256), (24, 64), 64), inception(512, 112, (144, 288), (32, 64), 64), inception(528, 256, (160, 320), (32, 128), 128), nn.MaxPool2d(3, 2,padding=1))
网络块5
self.block5 = nn.Sequential( inception(832, 256, (160, 320), (32, 128), 128), inception(832, 384, (182, 384), (48, 128), 128), nn.AvgPool2d(2) )
分类
self.classifier = nn.Linear(1024, class_out) def forward(self, x): x = self.block1(x) x = self.block2(x) x = self.block3(x) x = self.block4(x) x = self.block5(x)
将矩阵拉平
x = x.view(x.shape[0], -1) x = self.classifier(x) return x 注:由于篇幅问题,通道数的计算,在这里就不展示了,有兴趣的可以在小记当中观看。
3.定义损失函数和优化器
定义交叉熵损失函数和梯度下降函数优化器(学习率设定为0.01)。 Loss_f = nn.CrossEntropyLoss() optimizer = torch.optim.SGD(classify_GoogleNet.parameters(), lr=0.01)
二、模型训练
1、实例化模型
在实例化时,设定输入通道为3,输出类别数为10。 device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”) print(“device=”, device) classify_GoogleNet = googlenet(3, 10).to(device)
2、迭代训练
进行20次迭代训练 time1 = time.time() for k in range(20): train_loss = 0 train_acc = 0 classify_GoogleNet.train() # 将模型设为测试模式 for x_data, y_data in train_data: x_data = x_data.to(device) y_data = y_data.to(device)
前向传播
y_predict = classify_GoogleNet(x_data) loss_train = Loss_f(y_predict, y_data).to(device)
反向传播
optimizer.zero_grad() # 梯度清零 loss_train.backward() # 计算梯度 optimizer.step() # 使用优化器更新参数
记录误差
train_loss += loss_train
计算分类的准确率
_, pred = y_predict.max(1) train_correct = (pred == y_data).sum().item() / x_data.shape[0] train_acc += train_correct time_consume = time.time() - time1 print(’epoch:{},TrainLoss:{:.6f},TrainAcc:{:.6f},consume time:{:.3f}s’.format(k, train_loss / len(train_data), train_acc / len(train_data), time_consume)) torch.save(classify_GoogleNet.state_dict(), ‘classify_GoogleNet_params.pth’)
3、输出展示
与前两回相比,此次训练集训练的精度更高,损失值更低,但时间也是花费的更多。 epoch:0,TrainLoss:1.480232,TrainAcc:0.458440,consume time:302.479s epoch:4,TrainLoss:0.527561,TrainAcc:0.814978,consume time:1512.602s epoch:8,TrainLoss:0.212731,TrainAcc:0.926031,consume time:2728.588s epoch:12,TrainLoss:0.093475,TrainAcc:0.967032,consume time:3948.487s epoch:16,TrainLoss:0.055090,TrainAcc:0.980818,consume time:5171.283s epoch:19,TrainLoss:0.030331,TrainAcc:0.989950,consume time:6088.418s
总结
1、数据准备:准备CIFAR10数据集 2、模型准备:准备inception块,GoogleNet模型,交叉熵损失函数和优化器 3、数据训练:实例化训练模型,并进行20次数据训练。