代码是一个使用PyTorch实现的GoogLeNet模型,该模型是一个深度卷积神经网络(CNN)用于图像分类任务。
1. 定义基本卷积模块
BasicConv2d
类是一个基本的卷积块,包含一个卷积层、批归一化层和ReLU激活函数。该类用于构建Inception模块中的各分支。
# 导入torch库,torch是一个基于Python的科学计算框架,主要用于深度学习
import torch
# 导入torch.nn库,torch.nn是一个神经网络模块,提供了各种层和激活函数等
import torch.nn as nn
# 导入torchinfo库,torchinfo是一个用于打印模型结构和参数信息的库
from torchinfo import summary
# 定义一个基本的卷积层类,继承自nn.Module
class BasicConv2d(nn.Module):
# 定义初始化方法,接收输入通道数,输出通道数,以及其他可变参数
def __init__(self, inplanes, out_channels, **kwargs):
# 调用父类的初始化方法
super(BasicConv2d, self).__init__()
# 定义一个卷积模块,包含三个子层:卷积层,批归一化层,和ReLU激活层
self.conv = nn.Sequential(
# 定义一个卷积层,接收输入通道数,输出通道数,以及其他可变参数,不使用偏置项
nn.Conv2d(inplanes, out_channels, bias=False, **kwargs),
# 定义一个批归一化层,接收输出通道数
nn.BatchNorm2d(out_channels),
# 定义一个ReLU激活层,使用原地操作
nn.ReLU(inplace=True)
)
# 定义前向传播方法,接收输入张量x
def forward(self, x):
# 将x通过卷积模块,得到输出张量
x = self.conv(x)
# 返回输出张量
return x
2. 定义Inception层
Inception
类定义了Inception模块,包含四个分支:1x1卷积、1x1卷积后接3x3卷积、1x1卷积后接5x5卷积、最大池化后接1x1卷积。每个分支使用
BasicConv2d
构建。模块的输出是四个分支的拼接。
# 定义一个Inception模块类,继承自nn.Module
class Inception(nn.Module):
# 定义初始化方法,接收输入通道数,以及各个分支的输出通道数
def __init__(self, inplanes, ch1x1, ch3x3reduce, ch3x3, ch5x5reduce, ch5x5, pool_proj):
# 调用父类的初始化方法
super(Inception, self).__init__()
# 定义第一个分支,使用一个1x1的卷积层
self.branch1 = BasicConv2d(inplanes, ch1x1, kernel_size=1)
# 定义第二个分支,使用一个1x1的卷积层,后接一个3x3的卷积层,使用1的填充
self.branch2 = nn.Sequential(
BasicConv2d(inplanes, ch3x3reduce, kernel_size=1),
BasicConv2d(ch3x3reduce, ch3x3, kernel_size=3, padding=1)
)
# 定义第三个分支,使用一个1x1的卷积层,后接一个5x5的卷积层,使用2的填充
self.branch3 = nn.Sequential(
BasicConv2d(inplanes, ch5x5reduce, kernel_size=1),
BasicConv2d(ch5x5reduce, ch5x5, kernel_size=5, padding=2)
)
# 定义第四个分支,使用一个3x3的最大池化层,后接一个1x1的卷积层,使用1的填充
self.branch4 = nn.Sequential(
nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
BasicConv2d(inplanes, pool_proj, kernel_size=1)
)
# 定义前向传播方法,接收输入张量x
def forward(self, x):
# 将x分别通过四个分支,得到四个输出张量
branchh1 = self.branch1(x)
branchh2 = self.branch2(x)
branchh3 = self.branch3(x)
branchh4 = self.branch4(x)
# 将四个输出张量放入一个列表中
output = [branchh1, branchh2, branchh3, branchh4]
# 沿着通道维度,将列表中的张量拼接起来,得到最终的输出张量
return torch.cat(output, 1)
3. 定义一个辅助分类器类
AuxClf
类定义了辅助分类器,用于提供额外的梯度信息。包含特征提取部分和分类器部分。
特征提取部分包含平均池化和1x1卷积。
分类器部分包含两个全连接层。
# 定义一个辅助分类器类,继承自nn.Module
class AuxClf(nn.Module):
# 定义初始化方法,接收输入通道数,分类数,以及其他可变参数
def __init__(self, inplanes, num_classes, **kwargs):
# 调用父类的初始化方法
super(AuxClf, self).__init__()
# 定义一个特征提取模块,包含两个子层:平均池化层,和卷积层
self.feature_ = nn.Sequential(
# 定义一个平均池化层,使用5x5的核,3的步长
nn.AvgPool2d(kernel_size=5, stride=3),
# 定义一个卷积层,使用1x1的核,输出通道数为128
BasicConv2d(inplanes, 128, kernel_size=1)
)
# 定义一个分类模块,包含四个子层:线性层,ReLU激活层,Dropout层,和线性层
self.clf_ = nn.Sequential(
# 定义一个线性层,输入维度为4*4*128,输出维度为1024
nn.Linear(4*4*128, 1024),
# 定义一个ReLU激活层,使用原地操作
nn.ReLU(inplace=True),
# 定义一个Dropout层,使用0.7的丢弃率
nn.Dropout(0.7),
# 定义一个线性层,输入维度为1024,输出维度为分类数
nn.Linear(1024, num_classes)
)
# 定义前向传播方法,接收输入张量x
def forward(self, x):
# 将x通过特征提取模块,得到输出张量
x = self.feature_(x)
# 将输出张量展平为一维向量,维度为4*4*128
x = x.view(-1, 4*4*128)
# 将展平后的向量通过分类模块,得到输出向量
x = self.clf_(x)
# 返回输出向量
return x
4. 定义一个GoogLeNet类