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

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

文章目录

  • Pytorch 第八回:卷积神经网络——GoogleNet模型
  • 前言
    • 1、GoogleNet模型
    • 2、inception块
    • 3、批量规范化
    • 4、影响神经网络的训练因素有哪些,可以先总结一下:
  • 一、数据准备
  • 二、模型准备
    • 1.搭建inception块
    • 2.GoogleNet网络搭建
    • 3.定义损失函数和优化器
  • 二、模型训练
    • 1、实例化模型
    • 2、迭代训练
    • 3、输出展示
  • 总结


前言

讲解模型前,先分享几个概念,统一下思想:

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)
        )

        # 第二条线路 1*1卷积-> 3*3卷积+填充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)
        )
        # 第三条线路 1*1卷积-> 5*5卷积+填充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)
        )
        # 第四条线路 3*3池化+填充1-> 3*3卷积
        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次数据训练。


http://www.kler.cn/a/578488.html

相关文章:

  • SpringBoot 配置视图控制器
  • Android Activity的启动器ActivityStarter入口
  • 使用 Java 在后端 为 PDF 添加水印
  • 跟着 Lua 5.1 官方参考文档学习 Lua (11)
  • AtCoder ABC E - Min of Restricted Sum 题解
  • Etcd的安装与使用
  • Spring Boot拦截器(Interceptor)与过滤器(Filter)深度解析:区别、实现与实战指南
  • 通过定制initramfs实现从单系统分区到双系统的无缝升级
  • 手抖护理全攻略:从生活点滴改善症状
  • AI 智能:开拓未知疆域的科技先锋
  • 11-Agent中配置自己的插件
  • 芋道源码 —— Spring Boot 缓存 Cache 入门
  • 搭建农产品管理可视化,助力农业智能化
  • scala函数的至简原则
  • Android Retrofit + RxJava + OkHttp 网络请求高效封装方案
  • 线性表相关代码(顺序表+单链表)
  • C++蓝桥杯基础篇(九)
  • UE4 World, Level, LevelStreaming从入门到深入
  • 【Linux系统编程】初识系统编程
  • RMAN备份bug-审计日志暴涨(select action from gv$session)