当前位置:   article > 正文

GoogLeNet详解

googlenet

入门小菜鸟,希望像做笔记记录自己学的东西,也希望能帮助到同样入门的人,更希望大佬们帮忙纠错啦~侵权立删。

✨完整代码在我的github上,有需要的朋友可以康康✨

https://github.com/tt-s-t/Deep-Learning.git

目录

一、GoogLeNet网络的背景

二、GooLeNet网络结构

1、Inception模块

2、辅助分类器

3、GooLeNet网络

 三、GooLeNet的亮点

 1、引入Inception结构

 2、使用1x1的卷积核进行降维映射处理

3、添加两个辅助分类器帮助训练

4、使用全局平均池化

5、1*n和n*1卷积核并联代替n*n卷积核

 四、GooLeNet代码实现


一、GoogLeNet网络的背景

想要更好的预测效果,就要从网络深度和网络宽度两个角度出发增加网络的复杂度。

但这个思路有两个较为明显的问题:

首先,更复杂的网络意味着更多的参数,也很容易过拟合;

其次,更复杂的网络会消耗更多的计算资源,而且卷积核个数设计不合理,导致了卷积核中参数没有被完全利用(多数权重都趋近0)时,会造成大量计算资源的浪费。

因此GoogLeNet在专注于加深网络结构的同时,引入了新的基本结构——Inception模块,以增加网络的宽度。GoogLeNet一共22层,没有全连接层,在2014年的ImageNet图像识别挑战赛中获得了冠军。


二、GooLeNet网络结构

1、Inception模块

 Inception模块的基本组成结构有四个:1x1卷积,3x3卷积,5x5卷积,3x3最大池化。

最后再对四个成分运算结果进行通道上组合。

这就是Naive Inception(上图a)的核心思想:利用不同大小的卷积核实现不同尺度的感知,最后进行融合,可以得到图像更好的表征(即探索特征图上不同邻域内的“相关性”)。

Note:每个分支得到的特征矩阵高和宽必须相同。

但Naive Inception有两个缺点:

(1)所有卷积层直接和前一层输入的数据对接,所以卷积层中的计算量会很大(一变四);

(2)在这个单元中使用的最大池化层保留了输入数据的特征图的深度,所以在最后进行合并后总输出的特征图的深度一定会增加,这样增加了该单元之后的网络结构的计算量。

所以多加使用了1x1 卷积核主要目的是进行压缩降维,减少参数量(即上图b),从而让网络更深、更宽,更好的提取特征,这种思想也称为Pointwise Conv(逐点卷积),简称PW。

压缩降维:通过卷积层的输出通道数来调整这很好理解;

减少参数量:假设输入通道数为Cin,原本是直接要使用输出通道数为Cout的N*N卷积层来进行卷积,那么所需参数量为Cin*Cout*N*N;如果加上输出通道数为k的1*1卷积核的话,所需参数量为:Cin*k+N*N*Cout*k,只要k足够小就能使参数量大幅度下降了。

2、辅助分类器

因为神经网络的中间层也具有很强的识别能力,因此GooLeNet在一些中间层中添加了含有多层的分类器。

GoogLeNet中共增加了两个辅助的softmax分支。

网络结构如下图所示(其中的红圈圈就是辅助的分类器)

作用:

(1)为了避免梯度消失,用于向前传导梯度(反向传播时如果有一层求导为0,链式求导结果则为0)—— 最主要的原因;

(2)将中间某一层输出用作分类,起到模型融合作用(最终的分类结果以及这两个辅助分类器的结果(辅助分类按一个较小的权重加到最终分类结果中)一同决判出最终训练得到的分类结果)。但实际测试时,这两个辅助softmax分支会被去掉(因为辅助的主要原因是为了向前传导梯度,因此训练完后就没有价值了,理应扔掉)。

(3)正则化作用:

      在后续的研究中,Google团队研究人员发现辅助分类器在训练早期并没有改善收敛:在两个模型达到高精度之前,两种网络的训练进度看起来几乎相同;接近训练结束,有辅助分支的网络才开始超越没有任何分支的网络的准确性,达到了更高的稳定水平,因此辅助分类器更多的还是起到了一个正则化的作用(防止过拟合)。

3、GooLeNet网络

这是最初GooLeNet论文中展示的网络参数

 以下展示的是torchvision.models.GoogLeNet()的网络结构:

 其中Inception发生变化,将5*5卷积核部分也替换成了3*3卷积。

以下展示Inception3a:


 三、GooLeNet的亮点

 1、引入Inception结构

引入的Inception融合了不同尺度的特征信息,能得到更好的特征表征。

更意味着提高准确率,不一定需要堆叠更深的层或者增加神经元个数等,可以转向研究更稀疏但是更精密的结构同样可以达到很好的效果。

 2、使用1x1的卷积核进行降维映射处理

 降低了维度也减少了参数量(NiN是用于代替全连接层)。

3、添加两个辅助分类器帮助训练

避免梯度消失,用于向前传导梯度,也有一定的正则化效果,防止过拟合。

4、使用全局平均池化

用全局平均池化代替全连接层大大减少了参数量(与NiN一致)

5、1*n和n*1卷积核并联代替n*n卷积核

在InceptionV3中,在不改变感受野同时减少参数的情况下,采用1*n和n*1的卷积核并联来代替InceptionV1-V2中n*n的卷积核(发掘特征图的高的特征,以及特征图的宽的特征)。

这种方法在大维度的特征图上表现不好,在特征图12-20维度上表现好,若这种叠加的不对称分解卷积走高维路线,则更易训练(深层网络适合)。

降低了计算量和减少了参数量。


 四、GooLeNet代码实现

完整代码可以在我的github上看https://github.com/tt-s-t/Deep-Learning.git

在里面的GooLeNet文件夹中,分有调用torchvision.module.goolenet()实现的和自行搭建实现的

这里展示模型搭建代码

  1. import torch
  2. import torch.nn as nn
  3. import torch.nn.functional as F
  4. #conv+ReLU
  5. class BasicConv2d(nn.Module):
  6. def __init__(self, in_channels, out_channels, **kwargs):
  7. super(BasicConv2d, self).__init__()
  8. self.conv = nn.Conv2d(in_channels, out_channels, **kwargs)
  9. self.relu = nn.ReLU()
  10. def forward(self, x):
  11. x = self.conv(x)
  12. x = self.relu(x)
  13. return x
  14. #前部
  15. class Front(nn.Module):
  16. def __init__(self):
  17. super(Front, self).__init__()
  18. self.conv1 = BasicConv2d(3, 64, kernel_size=7, stride=2, padding=3)
  19. self.maxpool1 = nn.MaxPool2d(3, stride=2,ceil_mode=True)
  20. self.conv2 = BasicConv2d(64, 64, kernel_size=1)
  21. self.conv3 = BasicConv2d(64, 192, kernel_size=3, padding=1)
  22. self.maxpool2 = nn.MaxPool2d(3, stride=2,ceil_mode=True)
  23. def forward(self,input):
  24. #输入:(N,3,224,224)
  25. x = self.conv1(input)#(N,64,112,112)
  26. x = self.maxpool1(x)#(N,64,56,56)
  27. x = self.conv2(x)#(N,64,56,56)
  28. x = self.conv3(x)#(N,192,56,56)
  29. x = self.maxpool2(x)#(N,192,28,28)
  30. return x
  31. class Inception(nn.Module):
  32. def __init__(self, in_channels, ch1x1, ch3x3_1_1, ch3x3_1, ch3x3_2_1, ch3x3_2, pool_ch):
  33. super(Inception, self).__init__()
  34. self.branch1 = BasicConv2d(in_channels, ch1x1, kernel_size=1)
  35. self.branch2 = nn.Sequential(
  36. BasicConv2d(in_channels, ch3x3_1_1, kernel_size=1),
  37. BasicConv2d(ch3x3_1_1, ch3x3_1, kernel_size=3, padding=1)
  38. )
  39. self.branch3 = nn.Sequential(
  40. BasicConv2d(in_channels, ch3x3_2_1, kernel_size=1),
  41. BasicConv2d(ch3x3_2_1, ch3x3_2, kernel_size=3, padding=1)
  42. )
  43. self.branch4 = nn.Sequential(
  44. nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
  45. BasicConv2d(in_channels, pool_ch, kernel_size=1)
  46. )
  47. def forward(self, x):
  48. #输入(N,Cin,Hin,Win)
  49. branch1 = self.branch1(x)#(N,C1,Hin,Win)
  50. branch2 = self.branch2(x)#(N,C2,Hin,Win)
  51. branch3 = self.branch3(x)#(N,C3,Hin,Win)
  52. branch4 = self.branch4(x)#(N,C4,Hin,Win)
  53. outputs = [branch1, branch2, branch3, branch4]
  54. return torch.cat(outputs, 1)#(N,C1+C2+C3+C4,Hin,Win)
  55. #辅助分类器
  56. class InceptionAux(nn.Module):
  57. def __init__(self, in_channels, num_classes):
  58. super(InceptionAux, self).__init__()
  59. self.averagePool = nn.AvgPool2d(kernel_size=5, stride=3)
  60. self.conv = BasicConv2d(in_channels, 128, kernel_size=1)
  61. self.fc1 = nn.Linear(2048, 1024)
  62. self.fc2 = nn.Linear(1024, num_classes)
  63. def forward(self, x):
  64. # 输入:aux1:(N,512,14,14), aux2: (N,528,14,14)
  65. x = self.averagePool(x)# aux1:(N,512,4,4), aux2: (N,528,4,4)
  66. x = self.conv(x)# (N,128,4,4)
  67. x = torch.flatten(x, 1)# (N,2048)
  68. x = F.dropout(x, 0.5, training=self.training)
  69. x = F.relu(self.fc1(x))# (N,1024)
  70. x = F.dropout(x, 0.5, training=self.training)
  71. x = self.fc2(x)# (N,num_classes)
  72. return x
  73. # GooLeNet网络主体
  74. class GoogLeNet(nn.Module):
  75. def __init__(self, num_classes=1000, aux_logits=True):
  76. super(GoogLeNet, self).__init__()
  77. self.aux_logits = aux_logits
  78. self.front = Front()
  79. self.inception3a = Inception(192, 64, 96, 128, 16, 32, 32)
  80. self.inception3b = Inception(256, 128, 128, 192, 32, 96, 64)
  81. self.maxpool3 = nn.MaxPool2d(3, stride=2,ceil_mode=True)
  82. self.inception4a = Inception(480, 192, 96, 208, 16, 48, 64)
  83. self.inception4b = Inception(512, 160, 112, 224, 24, 64, 64)
  84. self.inception4c = Inception(512, 128, 128, 256, 24, 64, 64)
  85. self.inception4d = Inception(512, 112, 144, 288, 32, 64, 64)
  86. self.inception4e = Inception(528, 256, 160, 320, 32, 128, 128)
  87. self.maxpool4 = nn.MaxPool2d(3, stride=2,ceil_mode=True)
  88. self.inception5a = Inception(832, 256, 160, 320, 32, 128, 128)
  89. self.inception5b = Inception(832, 384, 192, 384, 48, 128, 128)
  90. if self.aux_logits:
  91. self.aux1 = InceptionAux(512, num_classes)
  92. self.aux2 = InceptionAux(528, num_classes)
  93. self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
  94. self.dropout = nn.Dropout(0.4)
  95. self.fc = nn.Linear(1024, num_classes)
  96. def forward(self, x):
  97. #输入:(N,3,224,224)
  98. x = self.front(x)#(N,192,28,28)
  99. x = self.inception3a(x)#(N,256,28,28)
  100. x = self.inception3b(x)#(N,480,28,28)
  101. x = self.maxpool3(x)#(N,480,14,14)
  102. x = self.inception4a(x)#(N,512,14,14)
  103. if self.training and self.aux_logits:
  104. aux1 = self.aux1(x)
  105. x = self.inception4b(x)#(N,512,14,14)
  106. x = self.inception4c(x)#(N,512,14,14)
  107. x = self.inception4d(x)#(N,528,14,14)
  108. if self.training and self.aux_logits:
  109. aux2 = self.aux2(x)
  110. x = self.inception4e(x)#(N,832,14,14)
  111. x = self.maxpool4(x)#(N,832,7,7)
  112. x = self.inception5a(x)#(N,832,7,7)
  113. x = self.inception5b(x)#(N,1024,7,7)
  114. x = self.avgpool(x)#(N,1024,1,1)
  115. x = torch.flatten(x, 1)#(N,1024)
  116. x = self.dropout(x)
  117. x = self.fc(x)#(N,num_classes)
  118. if self.training and self.aux_logits:
  119. return x, aux2, aux1
  120. return x

欢迎大家在评论区批评指正,谢谢~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/blog/article/detail/31757
推荐阅读
相关标签
  

闽ICP备14008679号