GoogleNet
一 论文导读
一 LeNet 如下图:
LeNet 是整个卷积神经网络的开山之作,是卷积神经网络的现代雏形,1998年LeCun提出
缺点是:网络层数浅,无激活层
二 AlexNet
AlexNet:2012年在ImageNet竞赛中取得了冠军,这是ImageNet竞赛史上第一次基于卷积神经网络模型得到冠军,AlexNet相对于LeNet,网络更深,同时第一次引入ReLu激活层,在全连接层引入Dropout层防止过拟合。
补充:Relu激活层标志着深度神经网络的出现
当时限于GPU运算量有限,使用两个GPU并行运算。
三 VGG
VggNet是第一个真正意义上的深层网络结构,是ImageNet2014年的亚军,使用了更小的滤波器,更深的网络结构
VGGNet与AlexNetb比较:AlexNet只有8层,VGGNet有16-19层,AlexNet使用了1111卷积滤波器,VGGNet使用了33卷积滤波器和2*2的最大池化层,层叠小的滤波器和大的滤波器感受野是相同的,还能减少参数,因而有更深的网络。
四 GoogleNet
GoogleNet也叫InceptionNet,是2014年ImageNet比赛的冠军,相比于VGGNet有更深的网络,但是网络参数却比AlexNet少12倍,计算效率非常高,因为GoogleNet采用了Inception模块,GoogleNet可以看作是很多个inception模块的串联,并且模型没有全连接。
Inception 模块设计了一种局部的网络拓扑结构,然后将这些模块堆叠在一起形成一个抽象的网络结构,运行及各个并行的滤波器,对输入进行卷积和池化,这些滤波器有着不同的感受野,最后将输出结果拼接在一起输出。
最原始Inception的基本结构:
一方面增加了网络宽度,另一方面也增加了网络对尺度的适应性。
网络卷积层中的网络能够提取输入的每一个细节信息,同时5*5
的滤波器也能够覆盖大部分接受层的输入。还可以进行一个池化操作,以减少空间大小,降低多度拟合。在这些层之上,在每一个卷积层后都要做一个Relu操作,以增加网络的非线性特征。
InceptionV2:
Inception原始版本,所有的卷积核都在上一层的所有输出上来做,而5*5
的卷积核所需的计算量很大,造成特征图的厚度很大,为了避免这种情况,在3*3
前,5*5
前、max pooling后分别加上1*1
的卷积核,已起到了降低特征图厚度的作用,这也就形成了Inception V1的网络结构。
InceptionV3:在不改变感受野同时减少参数的情况下,采用1*n
和n*1
的卷积核代替InceptionV1-V2中的n*n
的卷积核。
InceptionV4:
InceptionV4采用了inception模块于残差连接相结合,V4主要利用残差连接来改进V3结构,得到Inception-ResNet-V2,Inception-ResNet-V1的网络
五 ResNet
- ResNet是2015年ImageNet竞赛的冠军
- ResNet有效地解决了深度神经网络难以训练的问题,可以训练高达1000层的卷积神经网络
- ResNet通过引入了跨层链接解决了梯度回传消失的问题
- 使用普通的连接,上层的梯度必须要一层一层传回来,而采用残差连接,相当于中间有了一条更短的路,梯度能够从这条更短的路传回来,避免了梯度过小的情况。
论文的核心思想:
1*1Conv
-在
二 论文精读
三 代码实现
'''GoogLeNet with PyTorch.'''
import torch
import torch.nn as nn
import torch.nn.functional as F
# 卷积+bn+relu模块
class BasicConv2d(nn.Module):
def __init__(self, in_channels, out_channals, **kwargs):
super(BasicConv2d, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channals, **kwargs)
self.bn = nn.BatchNorm2d(out_channals)
def forward(self, x):
x = self.conv(x)
x = self.bn(x)
return F.relu(x)
# Inception模块
class Inception(nn.Module):
def __init__(self, in_planes,
n1x1, n3x3red, n3x3, n5x5red, n5x5, pool_planes):
super(Inception, self).__init__()
# 1x1 conv branch
self.b1 = BasicConv2d(in_planes, n1x1, kernel_size=1)
# 1x1 conv -> 3x3 conv branch
self.b2_1x1_a = BasicConv2d(in_planes, n3x3red,
kernel_size=1)
self.b2_3x3_b = BasicConv2d(n3x3red, n3x3,
kernel_size=3, padding=1)
# 1x1 conv -> 3x3 conv -> 3x3 conv branch
self.b3_1x1_a = BasicConv2d(in_planes, n5x5red,
kernel_size=1)
self.b3_3x3_b = BasicConv2d(n5x5red, n5x5,
kernel_size=3, padding=1)
self.b3_3x3_c = BasicConv2d(n5x5, n5x5,
kernel_size=3, padding=1)
# 3x3 pool -> 1x1 conv branch
self.b4_pool = nn.MaxPool2d(3, stride=1, padding=1)
self.b4_1x1 = BasicConv2d(in_planes, pool_planes,
kernel_size=1)
def forward(self, x):
y1 = self.b1(x)
y2 = self.b2_3x3_b(self.b2_1x1_a(x))
y3 = self.b3_3x3_c(self.b3_3x3_b(self.b3_1x1_a(x)))
y4 = self.b4_1x1(self.b4_pool(x))
# y的维度为[batch_size, out_channels, C_out,L_out]
# 合并不同卷积下的特征图
return torch.cat([y1, y2, y3, y4], 1)
class GoogLeNet(nn.Module):
def __init__(self):
super(GoogLeNet, self).__init__()
self.pre_layers = BasicConv2d(3, 192,
kernel_size=3, padding=1)
self.a3 = Inception(192, 64, 96, 128, 16, 32, 32)
self.b3 = Inception(256, 128, 128, 192, 32, 96, 64)
self.maxpool = nn.MaxPool2d(3, stride=2, padding=1)
self.a4 = Inception(480, 192, 96, 208, 16, 48, 64)
self.b4 = Inception(512, 160, 112, 224, 24, 64, 64)
self.c4 = Inception(512, 128, 128, 256, 24, 64, 64)
self.d4 = Inception(512, 112, 144, 288, 32, 64, 64)
self.e4 = Inception(528, 256, 160, 320, 32, 128, 128)
self.a5 = Inception(832, 256, 160, 320, 32, 128, 128)
self.b5 = Inception(832, 384, 192, 384, 48, 128, 128)
self.avgpool = nn.AvgPool2d(8, stride=1)
self.linear = nn.Linear(1024, 5)
def forward(self, x):
out = self.pre_layers(x)
out = self.a3(out)
out = self.b3(out)
out = self.maxpool(out)
out = self.a4(out)
out = self.b4(out)
out = self.c4(out)
out = self.d4(out)
out = self.e4(out)
out = self.maxpool(out)
out = self.a5(out)
out = self.b5(out)
out = self.avgpool(out)
out = out.view(out.size(0), -1)
out = self.linear(out)
return out