深度学习-一篇入门

【模型】一篇入门之-Inception-v1(GoogLeNet)卷积神经网络

作者 : 老饼 发表日期 : 2024-03-04 19:03:52 更新日期 : 2024-10-31 07:25:51
本站原创文章,转载请说明来自《老饼讲解-深度学习》www.bbbdata.com




Inception模型是一系列以Inception模块为特色的卷积神经网络,共有4个版本,第一个版本也称为GoogLeNet模型

本文讲解Inception-V1的模型结构与配置,以及展示pytorch实现Inception-V1(GoogLeNet)的具体代码

通过本文,可以了解Inception-V1、GoogLeNet模型是什么,以及如何使用GoogLeNet来实现图像类别识别





     01. Inception-V1(GoogLeNet)模型是什么     




本节讲解GoogLeNet-Inception-V1的模型结构,快速了解Inception-V1是什么





     什么是Inception-V1(GoogLeNet)卷积神经网络      


Inception系列模型是由谷歌团队开发的一种以Inception模块为特色的卷积神经网络
Inception系列目前共有4个版本,它的第一个版本在2014年提出,并取得了ILSVRC-2014分类任务冠军
当时第一个版本致敬LeNet,取名为GoogLeNet,但有了其它版本后,现在一般称为Inception-V1模型
Inception-V1的原文提供的模型结构图如下:

 
 由于原文的结构图比较头晕,笔者整理后的Inception-V1模型结构如下:
  
可以看到,GoogLeNet的整个结构由C1-C5、F6共6大层组成
 👉1. C1和C2是传统的卷积层                             
👉2. C3-C5则是由Inception模块堆积的卷积层 
👉3. F6是全连接层                                          

总的来说,整个GoogLeNet的侧重点就在于加入了Inception模块,其它的都是继承AlexNet的思想
 GoogLeNet模型辅助器说明
GoogLeNet还在模型中还添加了两个预测分支(辅助器0和辅助器1)
它们只用于训练阶段辅助模型训练浅层的模型参数,并不参与最后的模型应用
 训练阶段,两个辅助器也同时进行反向传播更新浅层的权重、阈值,
但它们只作为辅助,所以它们在训练时的影响需要削弱,在更新时,只以30%作为权重、阈值的迭代量

GoogLeNet原文加入辅助器是希望浅层能尽快抓住类别特征,但后面的论文发现作用不大,渐渐一般不再使用







    02. Inception-V1-结构详述   




本节讲解GoodLeNet-Inception-V1模型的详细配置和具体的运算逻辑




    Inception-V1结构与配置详述    


从模型流程图可以看到,Inception-V1(GoodLeNet)是一个相对复杂的模型
它包含了并行部分,因此不能以流式直接描述它运算的流程与配置
因此,我们对其分为三部分进行描述:
 👉1. Inception的配置格式与具体运算逻辑                 
👉2. GoodLeNet-Inception-V1模型的主流程配置   
👉3. 侧头辅助器                                                       
 
下面我们分别描述这三部分的配置与运算过程:
 
一、Inception-V1模块的配置格式
 Inception-V1模块的结构图如下
 

 其中,输入通道数、每个卷积(共6个)的通道数是待定参数
不妨以下述格式作为Inception-V1模块的配置格式:
 
 C  :输入通道数                                       
C1 :Inception内部1×1卷积层的输出通道数              
C21:Inception内部3×3卷积层的输出通道数              
C31:Inception内部5×5卷积层的输出通道数              
       C20:Inception内部3×3卷积层之前的1×1降维卷积层的输出通道数 
       C30:Inception内部5×5卷积层之前的1×1降维卷积层的输出通道数 
   C4 :Inception内部池化层之后的1×1降维卷积层的输出通道数 

一个Inception-V1模块的详细运算流程如下:
 
 Inception-V1模型的详细配置      
 
GoodLeNetinception-V1的主流程的配置与运算流程如下:
 
  
 
  GoogLeNet辅助器的参数与运算流程     
两个辅助器的流程基本是一致的,只是输入的通道数不同,导致卷积层的输入通道不同,其它是一致的
 两个辅助器的具体参数和运算流程如下   
 Inception-V1辅助器0的配置 
Inception-V1辅助器1的配置







    03. Inception-V1-代码实现   




本节讲解Inception-v1(GoogLeNet)模型的代码实现与使用示例





       Inception-v1(GoogLeNet)-代码实现     


在pytorch中可以用googlenet来构建一个InceptionV1模型
下面我们打印出pytroch的googlenet模型结构:
  from torchvision import models                                                                                                      
  model = models.googlenet(init_weights=False)               # 初始化GoogLeNet模型(InceptionV1)  
  print('\n GoogLeNet的模块:\n',dict(model.named_children()))  # 打印GoogLeNet模型结构            

 
可以看到,Pytorch所提供的GoogLeNet模型会与原文多多少少有些小出入,其它的深度学习框架也是一样
 例如,在Pytorch的GoogLeNet中,没有使用LRN局部归一化,而是使用BN批归一化
因为毕竟GoogLeNet是较早的模型,随着时间的推移,一些无效的内容在实践中就会被淘汰
因此,GoogLeNet原文中的模型结构更多是学习时作为模型基准,而在实践中应灵活变通,与时俱进






    Inception-V1(GoogLeNet)-代码实现     


下面展示如何训练一个Inception-V1卷积神经网络用于图片类别识别
 具体代码如下:
import torchvision
import torch
from   torch.utils.data   import DataLoader
import numpy as np
model = torchvision.models.googlenet(num_classes=102)                          # 初始化模型
print('\n googlenet的模块:\n',dict(model.named_children()) ) 
# 训练函数                                                                   
def train(dataloader,valLoader,model,epochs,goal,device):                    
    for epoch in range(epochs):                                              
        err_num  = 0                                                         # 本次epoch评估错误的样本
        eval_num = 0                                                         # 本次epoch已评估的样本
        print('-----------当前epoch:',str(epoch),'----------------')         
        for batch, (imgs, labels) in enumerate(dataloader):                  
		    # -----训练模型-----                                             
            x, y = imgs.to(device), labels.to(device)                        # 将数据发送到设备
            optimizer.zero_grad()                                            # 将优化器里的参数梯度清空
            py   = model(x)                                                  # 计算模型的预测值 
            loss=lossFun(py.logits, y)                                        # 计算损失函数值
            +0.3*lossFun(py.aux_logits1, y)
            +0.3*lossFun(py.aux_logits2, y)
            loss.backward()                                                  # 更新参数的梯度
            optimizer.step()                                                 # 更新参数
			# ----计算错误率----                                             
            idx      = torch.argmax(py.logits,axis=1)                        # 模型的预测类别
            eval_num = eval_num + len(idx)                                   # 更新本次epoch已评估的样本
            err_num  = err_num +sum(y != idx)                                # 更新本次epoch评估错误的样本
            if(batch%10==0):                                                 # 每10批打印一次结果
                print('err_rate:',err_num/eval_num)                          # 打印错误率
        # -----------验证数据误差---------------------------                 
        model.eval()                                                         # 将模型调整为评估状态
        val_acc_rate = calAcc(model,valLoader,device)                        # 计算验证数据集的准确率
        model.train()                                                        # 将模型调整回训练状态
        print("验证数据的准确率:",val_acc_rate)                              # 打印准确率    
        if((err_num/eval_num)<=goal):                                        # 检查退出条件
            break                                                            
    print('训练步数',str(epoch),',最终训练误差',str(err_num/eval_num))       

# 计算数据集的准确率                                                         
def calAcc(model,dataLoader,device):                                         
    py = np.empty(0)                                                         # 初始化预测结果
    y  = np.empty(0)                                                         # 初始化真实结果
    for batch, (imgs, labels) in enumerate(dataLoader):                      # 逐批预测
        cur_py =  model(imgs.to(device))                                     # 计算网络的输出
        cur_py = torch.argmax(cur_py,axis=1)                                 # 将最大者作为预测结果
        py     = np.hstack((py,cur_py.detach().cpu().numpy()))               # 记录本批预测的y
        y      = np.hstack((y,labels))                                       # 记录本批真实的y
    acc_rate = sum(y==py)/len(y)                                             # 计算测试样本的准确率
    return acc_rate                                                             

# -------模型参数初始化----------------------
def init_param(model):
    param_dict = dict(model.named_parameters())                              # 获取模型的参数字典
    for key in  param_dict:                                                  # 历遍每个参数,对其初始化
        param_name = key.split(".")[-1]                                      # 获取参数的尾缀作为名称
        if (param_name=='weight'):                                           # 如果是权重
            torch.nn.init.normal_(param_dict[key])                           # 则正态分布初始化
        elif (param_name=='bias'):                                           # 如果是阈值
            torch.nn.init.zeros_(param_dict[key])                            # 则初始化为0
            
            
#-------------主流程脚本----------------------------------
#-------------------加载数据-----------------------
trainsform =torchvision.transforms.Compose([
    torchvision.transforms.Resize([224, 224]),
    torchvision.transforms.ToTensor(),
    ]
    )
train_data = torchvision.datasets.Flowers102(                               
    root       = 'D:\pytorch\data'                                           # 路径,如果路径有,就直接从路径中加载,如果没有,就联网获取
    ,split     ='train'                                                      # 训练数据
    ,transform = trainsform                                                  # 转换数据
    ,download  = True                                                        # 是否下载,选为True,就下载到root下面
    ,target_transform= None)                                                                         
val_data = torchvision.datasets.Flowers102(                                 
    root       = 'D:\pytorch\data'                                           # 路径,如果路径有,就直接从路径中加载,如果没有,就联网获取
    ,split     ='test'                                                       # 测试数据
    ,transform = trainsform                                                  # 转换数据
    ,download  = True                                                        # 是否下载,选为True,就下载到root下面
    ,target_transform= None)                                                 
                                                                             
#-------------------模型训练--------------------------------                 
trainLoader = DataLoader(train_data, batch_size=30, shuffle=True)            # 将数据装载到DataLoader
valLoader   = DataLoader(val_data  , batch_size=30)                          # 将验证数据装载到DataLoader 
device      = torch.device('cuda' if torch.cuda.is_available() else 'cpu')   # 设置训练设备  
init_param(model)                                                            # 初始化模型参数
model       = model.to(device)                                               # 发送到设备  
lossFun     = torch.nn.CrossEntropyLoss()                                    # 定义损失函数为交叉熵损失函数
optimizer   = torch.optim.SGD(model.parameters(), lr=0.01,momentum =0.9)     # 初始化优化器
train(trainLoader,valLoader,model,1000,0.01,device)                          # 训练模型,训练100步,错误低于1%时停止训练

# -----------模型效果评估--------------------------- 
model.eval()                                                                 # 将模型切换到评估状态(屏蔽Dropout)
train_acc_rate = calAcc(model,trainLoader,device)                            # 计算训练数据集的准确率
print("训练数据的准确率:",train_acc_rate)                                     # 打印准确率
val_acc_rate = calAcc(model,valLoader,device)                                # 计算验证数据集的准确率
print("验证数据的准确率:",val_acc_rate)       
备注:代码未亲测,仅供参考





好了,上述就是GoogLeNet-Inception-V1的模型结构的全部介绍内容了~







 End 




联系老饼