一位深度学习小萌新的学渣笔记(四)GoogLeNet网络介绍及代码详解

前言

继续学习霹雳大神的神经网络讲解视频

更新不易,希望大家可以去看原视频支持up主霹雳吧啦Wz

GoogLeNet网络详解
使用pytorch搭建GoogLeNet网络

本博文记载的是基于Pytorch框架的GoogLeNet网络

GoogLeNet网络结构详解与模型的搭建

简单介绍GoogLeNet网络

GoogLeNet网络在2014年被谷歌团队提出 LeNet大写是为了致敬LeNet

网络亮点:

  • 引入了Inception结构(融合不同尺度的特征信息)
  • 使用1 x 1的卷积核进行降维以及映射处理
  • 添加两个辅助分类器帮助训练
  • 在这里插入图片描述

// AlexNet和VGG都只有一个输出层 GoogLeNet有三个输出层(其中有两个辅助分类层)

  • 丢弃全连接测层,使用平均池化层(大大减少模型参数)

模型结构

在这里插入图片描述
结构分析

input
卷积层
最大下采样层
LocalRespNorm层
卷积层
卷积层
LocalRespNorm层
最大下采样层

Inception层(3a)
在这里插入图片描述
lnception(3b)
在这里插入图片描述
最大池化层
Inception(4a)
在这里插入图片描述
黄色部分是辅助分类器1
在这里插入图片描述
在这里插入图片描述
softmax激活函数进行输出
在这里插入图片描述

Inception模型

初始的版本

在这里插入图片描述
将上一层的输出同时输入到四个分支中进行处理 处理之后将我们得到的这四个分支的特征矩阵按照深度进行拼接 得到我们的输出特征矩阵

注意:每个分支得到的特征矩阵的高和宽必须相同 否则无法沿深度方向进行拼接

优化后的版本

在这里插入图片描述
Inception结构加上一个降维的功能
用到了三个1 x 1的卷积层 进行降维

1x1的卷积核如何起到降维的作用呢?

在这里插入图片描述
这样子使用1x1的卷积核 目的是为了减少特征矩阵的深度,从而减少我们的参数个数 ,也就减少了我们的计算量

辅助分类器

两个辅助分类器的结构一样
在这里插入图片描述
**第一层是我们的平均下采样操作,池化核大小是5*5 ,步距是等于3 **
第一个辅助分类器是来自于我们的inception4a的输出
inception4a的输出矩阵的大小是14x14x512

第二个辅助分类器是来自于我们的inception4d的输出
inception4d的输出矩阵的大小是14x14x528

两个分类器的输出矩阵高度与宽度相同 但是深度不一样

计算一下AveragePool的输出
根据out(size)=in(size)- F(size)+2 P / S+1
可以计算得到out = (14 -5 )/ 3 + 1 = 4
而平均下采样层又不会改变输入矩阵的深度
所以第一个输出分类器AveragePool层的输出是4x4x512
所以第二个输出分类器AveragePool层的输出是4x4x528

采用128个卷积核大小为1*1的卷积层进行卷积处理,目的是为了降低维度,并且使用的是ReLU激活函数

采用节点个数为1024的全连接层,同样使用ReLU激活函数

全连接层与全连接层之间使用dropout函数,以70%的比例,随机失活神经元

采用节点个数为1000的全连接层,这里的节点个数是对应我们的类别个数!!!

通过softmax函数得到我们的概率分布

理解参数

在这里插入图片描述
表格数据从上到下 一一对应GoogLeNet的每一层结构的数据
LocalRespNorm层起到的作用不大 可以舍弃掉
辅助分类器的参数前面有详细讲解
池化层的参数表示是类似5x5+2(V) 表示的是5x5的大小 2的步长
而卷积层参数表示是5x5+2(S) 表示的是5x5的大小 2的步长
注意最后avg pool与全连接层直接还有一个dropout函数 是以40%的概率随机失活神经元

inception结构的对应 如下图所示

在这里插入图片描述

model.py代码解读

创建GoogLeNet网络之前先创建几个模板文件

首先是我们的BasicConv2d
因为我们在构建我们的卷积层的时候通常是将我们的卷积和我们的ReLU激活函数绑定在一起
所以创建一个常用的class BasicConv2d

定义BasicConv2d


class BasicConv2d(nn.Module):#继承于nn.Module
    def __init__(self, in_channels, out_channels, **kwargs):#参数有输出特征层的深度 输出矩阵特征层的深度 
        super(BasicConv2d, self).__init__()
        self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)#定义卷积层 
        #输入特征矩阵深度就是我in_channels,卷积核的个数就是我们输出特征矩阵的深度
        self.relu = nn.ReLU(inplace=True)#定义ReLU激活函数

    def forward(self, x):#定义一个正向传播过程
        x = self.conv(x)
        x = self.relu(x)
        return x

定义Inception结构

class Inception(nn.Module):#继承自nn.Module
    def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
    #参数分析:输入特征矩阵的深度,ch1x1代表#1x1 ch3x3red代表#3x3 reduce   
    #ch5x5red代表#5x5 reduce   ch5x5代表#5x5  pool_pro代表pool proj
        super(Inception, self).__init__()

        self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
		#分支1   使用BasicConv2d模板(我们输入特征矩阵的深度,采用卷积核的个数,卷积核大小,步距是1是默认的)
        self.branch2 = nn.Sequential(
            BasicConv2d(in_channels, ch3x3red, kernel_size=1),
            BasicConv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)   # 保证输出大小等于输入大小
        )
        #分支2使用nn.Sequential函数
        #使用BasicConv2d(输入特征矩阵的深度,采用卷积核的个数,卷积核大小是1x1,步距是1是默认的)
        #使用BasicConv2d模板(输入特征矩阵的深度这时候就是ch3x3red是上一层输出矩阵的深度,采用卷积核的个数,卷积核大小为3x3,步距是1是默认的)
        #为了保证每个分支所输出的高度和宽度相同,所以必须设置padding为1
        #output_size=(input_size-3+2*1)/1+1=input_size
        

        self.branch3 = nn.Sequential(
            BasicConv2d(in_channels, ch5x5red, kernel_size=1),
            BasicConv2d(ch5x5red, ch5x5, kernel_size=5, padding=2)   # 保证输出大小等于输入大小
        )
        #分支3 使用nn.Sequential函数
        #使用BasicConv2d(输入特征矩阵的深度,采用卷积核的个数,卷积核大小是1x1,步距是1是默认的)
		#使用BasicConv2d模板(输入特征矩阵的深度这时候就是ch5x5red是上一层输出矩阵的深度,采用卷积核的个数,卷积核大小为5x5,步距是1是默认的)
        #为了保证每个分支所输出的高度和宽度相同,所以必须设置padding为2
        #output_size=(input_size-5+2*2)/1+1=input_size
        
        self.branch4 = nn.Sequential(
            nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
            BasicConv2d(in_channels, pool_proj, kernel_size=1)
        )
	 	#分支4 使用nn.Sequential函数
	 	#使用nn.MaxPool2d(卷积核大小为3x3,步距是1,padding是1)
	 	#为了保证每个分支所输出的高度和宽度相同,stride设置为1,设置padding为1
		#使用BasicConv2d模板(输入矩阵的深度,采用卷积核的个数是pool_proj,卷积核大小为1x1)   
      
    def forward(self, x): #定义正向传播过程
    #将我们的特征矩阵分别输入到branch1、branch2.。。。 分别得到这四个分支所对应的输出
        branch1 = self.branch1(x)
        branch2 = self.branch2(x)
        branch3 = self.branch3(x)
        branch4 = self.branch4(x)

        outputs = [branch1, branch2, branch3, branch4] #将我们的的输出放入一个列表当中
        return torch.cat(outputs, 1)#使用一个torch.cat函数对我们的四个分支的输出进行合并,第一个参数是输出特征的列表,需要合并的一个维度,我们序呀在需要在深度方向上进行合并 
        #tensor的参数是(batch,channel,高度,宽度)

定义辅助分类器


class InceptionAux(nn.Module):#定义自nn.Module这个父类
    def __init__(self, in_channels
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值