理论基础:
Inception网络是一种深度卷积神经网络架构,首次在 2014 年的 ILSVRC(ImageNet Large - Scale Visual Recognition Challenge)大赛中获得了冠军,它在现代深度学习中具有重要的影响。主要创新点在于其独特的模块化结构和多尺寸卷积的组合方式,能够在不同尺度上提取图像特征,从而提高网络对图像内容的理解能力。下面是 Inception 网络的详细结构和特点介绍。
Inception 模块
Inception 模块的核心思想是将多个不同大小的卷积核和池化操作组合在一起,同时对输入数据进行处理。
Inception 网络的核心是它的 Inception 模块。这个模块允许网络在同一层中使用多种卷积核大小,并通过并行处理不同的特征图来提取丰富的特征。一个典型的 Inception 模块包含以下几个主要组件:
1x1 卷积:用于减少通道数,这种卷积可以有效降低计算量和参数数量。
1x1 + 3x3 卷积:将输入先通过一个 1x1 的卷积层进行降维,接着通过一个 3x3 的卷积层提取特征。这种组合有助于捕获局部特征,同时保持较少的计算复杂度。
1x1 + 5x5 卷积:类似于上面的组合,用于捕获更大的特征。
3x3 最大池化:一般会跟一个 1x1 卷积层,这样可以在池化操作后增加非线性。
并行结构:所有这些操作的输出在深度方向上拼接在一起,形成模块的输出。这使得网络能够从多种卷积核大小获得信息。
工作原理
输入数据同时经过 1×1 卷积、3×3 卷积、5×5 卷积和 3×3 最大池化这四个分支。这些分支的输出在通道维度上进行拼接(concatenate),形成最终的输出。这样的设计使得网络能够自动学习不同尺度的特征,而不需要人工去确定哪种尺度的特征提取方式是最优的。例如,对于一幅包含不同大小物体的图像,小物体的特征可以通过 3×3 卷积分支更好地提取,而大物体的特征可能通过 5×5 卷积分支更有效地捕捉,同时 1×1 卷积可以对特征进行整合和优化,最大池化可以突出主要特征。
Inception 网络的结构
Inception 网络通常采用多个 Inception 模块堆叠而成,具体结构如下:
输入层:一般使用固定大小的图像输入,例如 224x224x3 的图像。
初始卷积层:使用一个大卷积核(通常是 7x7)进行初始特征提取。
最大池化层:在初始卷积后,通常会使用一个步幅为 2 的最大池化层。
多个 Inception 模块堆叠:
在网络的前面部分(前几层),使用较少的 Inception 模块。
随着层数的增加,逐渐增加 Inception 模块的数量。具体的 Inception 网络版本(如 GoogLeNet v1)通常包含 9 个 Inception 模块。
平均池化层:在最后一组 Inception 模块后,通常会添加一个全局平均池化层,以减少特征图的维度。
全连接层:最后,将特征图输入全连接层进行分类,输出最终的预测结果。
每个 Inception 版本的改进
GoogLeNet (Inception v1): 在模块内部组合多个卷积层,同时引入 1x1 卷积以减少计算。
Inception v2: 在 Inception v1 的基础上引入了批量归一化,并改进了模块的设计。
Inception v3: 更进一步优化了模型的计算效率,使用了更深的网络和更多的卷积层。
Inception v4: 在模块结构上进行了更多的改进,并引入了一些新的模块以提高网络的表现和效率。
优势和应用
计算效率:Inception 网络通过使用 1x1 卷积有效减少了参数量和计算资源需求。
多尺度特征提取:通过同时使用多种卷积核大小,Inception 网络能够在同一层中提取不同尺度的特征。
表现优异:在许多图像分类、物体检测和图像分割等任务中,Inception 网络表现出色。
应用场景
图像分类
Inception 网络在图像分类任务中表现出色。例如在 ImageNet 数据集上,能够准确地对各种物体的图像进行分类,如区分不同种类的动物、植物、交通工具等。
目标检测
在基于深度学习的目标检测框架中,Inception 网络可以作为特征提取器。例如在 Faster R - CNN 等目标检测算法中,利用 Inception 网络提取的特征来定位和识别图像中的目标物体。
其他视觉任务
还可以应用于图像分割、人脸识别等多种计算机视觉任务,为这些任务提供强大的特征提取基础
总结
Inception 网络通过其独特的模块化设计和并行计算能力,成功地提升了卷积神经网络的特征提取能力。它在计算效率和性能上都达到了很好的平衡,因此在众多计算机视觉任务中得到了广泛的应用。在深度学习的不断发展中,Inception 网络仍然是一个重要的研究和应用方向。
代码实现:
新建inception.py
import torch
import torch.nn as nn
import torch.nn.functional as F
def conv_block(in_channels, out_channels, kernel_size): # 定义通用的卷积块
return nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=1, padding=kernel_size // 2), # 卷积,注意双斜杠整除
nn.BatchNorm2d(out_channels),
nn.ReLU()
)
class InceptionBlock(nn.Module): # 定义一个InceptionBlock基本类
def __init__(self, in_channels, out_channels_list, reduce_channel_list):
super(InceptionBlock, self).__init__()
self.branch1 = conv_block(in_channels, out_channels_list[0], 1) # 定义分支1,1x1卷积块
self.branch2_conv1 = conv_block(in_channels, reduce_channel_list[0], 1) # 定义分支2的第一层,压缩卷积块
self.branch2_conv2 = conv_block(reduce_channel_list[0], out_channels_list[1], 3) # 定义分支2的第二层,3*3卷积块
self.branch3_conv1 = conv_block(in_channels, reduce_channel_list[1], 1) # 定义分支3的第一层,压缩卷积块
self.branch3_conv2 = conv_block(reduce_channel_list[1], out_channels_list[2], 5) # 定义分支3的第二层,5*5卷积块
self.branch4_pool = nn.MaxPool2d(kernel_size=3, stride=1, padding=1) # 定义分支4,最大池化层
self.branch4_conv = conv_block(in_channels, out_channels_list[3], 3) # 定义分支4,卷积块
def forward(self, x):
out1 = self.branch1(x)
out2 = self.branch2_conv1(x)
out2 = self.branch2_conv2(out2)
out3 = self.branch3_conv1(x)
out3 = self.branch3_conv2(out3)
out4 = self.branch4_pool(x)
out4 = self.branch4_conv(out4)
return torch.cat([out1, out2, out3, out4], dim=1) # 按照通道拼接
class InceptionNet(nn.Module):
def __init__(self):
super(InceptionNet, self).__init__()
self.block1 = nn.Sequential( # 定义第1个卷积层
nn.Conv2d(3, 64, kernel_size=7, stride=2, padding=1), nn.BatchNorm2d(64), nn.ReLU()
)
self.block2 = nn.Sequential( # 定义第2个卷积层
nn.Conv2d(64, 128, kernel_size=3, stride=2, padding=1), nn.BatchNorm2d(128), nn.ReLU()
)
self.block3 = nn.Sequential( # 定义第3个卷积层
InceptionBlock(in_channels=128,
out_channels_list=[64, 64, 64, 64], reduce_channel_list=[16, 16]),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.block4 = nn.Sequential( # 定义第4个卷积层
InceptionBlock(in_channels=256,
out_channels_list=[96, 96, 96, 96], reduce_channel_list=[32, 32]),
nn.MaxPool2d(kernel_size=3, stride=2, padding=1)
)
self.fc = nn.Linear(384, 10)
def forward(self, x):
out = self.block1(x)
out = self.block2(out)
out = self.block3(out)
out = self.block4(out)
out = torch.nn.functional.avg_pool2d(out, 2)
out = out.view(out.size(0), -1)
out = self.fc(out)
return out
def InceptionNet_small():
return InceptionNet()
用新建的网络及进行训练:
同样的,将之前的train.py脚本中的
net = resnet().to(device),改为:
net = InceptionNet_small().to(device),即可运行开始训练: