inception.py

发布时间 2023-06-12 16:47:09作者: 王哲MGG_AI
import torch
import torch.nn as nn
import torchvision.utils
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F
'''
假如输入为(35, 35, 192)的数据:

第一个branch:
经过branch1x1为带有64个1*1的卷积核,所以生成第一张特征图(35, 35, 64);
第二个branch:
首先经过branch5x5_1为带有48个1*1的卷积核,所以第二张特征图(35, 35, 48),
然后经过branch5x5_2为带有64个5*5大小且填充为2的卷积核,特征图大小依旧不变,因此第二张特征图最终为(35, 35, 64);
第三个branch:
首先经过branch3x3dbl_1为带有64个1*1的卷积核,所以第三张特征图(35, 35, 64),
然后经过branch3x3dbl_2为带有96个3*3大小且填充为1的卷积核,特征图大小依旧不变,因此进一步生成第三张特征图(35, 35, 96),
最后经过branch3x3dbl_3为带有96个3*3大小且填充为1的卷积核,特征图大小和通道数不变,因此第三张特征图最终为(35, 35, 96);
第四个branch:
首先经过avg_pool2d,其中池化核3*3,步长为1,填充为1,所以第四张特征图大小不变,通道数不变,第四张特征图为(35, 35, 192),
然后经过branch_pool为带有pool_features个的1*1卷积,因此第四张特征图最终为(35, 35, pool_features);
最后将四张特征图进行拼接,最终得到(35,35,64+64+96+pool_features)的特征图。'''
# 3 2 2 1
class InceptionA(torch.nn.Module):
def __init__(self, in_Channels, out_Channels ): # inChannels表输入通道数
super(InceptionA, self).__init__()
# 2.1 第一层池化 + 1*1卷积
self.branch1_1x1 = nn.Conv2d(in_Channels, # 输入通道
out_Channels//8*3, # 输出通道
kernel_size=1) # 卷积核大小1*1
# 2.2 第二层1*1卷积
self.branch2_1x1 = nn.Conv2d(in_Channels,out_Channels//8*2, kernel_size=1)

# 2.3 第三层
self.branch3_1_1x1 = nn.Conv2d(in_Channels, out_Channels//8*2, kernel_size=1)
self.branch3_2_5x5 = nn.Conv2d(out_Channels//8*2, out_Channels//8*2, kernel_size=5, padding=2)
# padding=2,因为要保持输出的宽高保持一致

# 2.4 第四层
self.branch4_1_1x1 = nn.Conv2d(in_Channels, out_Channels//8*1, kernel_size=1)
self.branch4_2_3x3 = nn.Conv2d(out_Channels//8*1, out_Channels//8*1, kernel_size=3, padding=1)
self.branch4_3_3x3 = nn.Conv2d(out_Channels//8*1, out_Channels//8*1, kernel_size=3, padding=1)

def forward(self, X_input):
# 第一层
branch1_pool = F.avg_pool2d(X_input, # 输入
kernel_size=3, # 池化层的核大小3*3
stride=1, # 每次移动一步
padding=1)
branch1 = self.branch1_1x1(branch1_pool)
# 第二层
branch2 = self.branch2_1x1(X_input)
# 第三层
branch3_1 = self.branch3_1_1x1(X_input)
branch3 = self.branch3_2_5x5(branch3_1)
# 第四层
branch4_1 = self.branch4_1_1x1(X_input)
branch4_2 = self.branch4_2_3x3(branch4_1)
branch4 = self.branch4_3_3x3(branch4_2)
# 输出
output = [branch2, branch3, branch4, branch1]
# (batch_size, channel, w, h) dim=1: 即安装通道进行拼接。
# eg: (1, 2, 3, 4) 和 (1, 4, 3, 4)按照dim=1拼接,则拼接后的shape为(1, 2+4, 3, 4)
return torch.cat(output, dim=1)


# # 3. 整合模型
# class Net(torch.nn.Module):
# def __init__(self):
# super(Net, self).__init__()
# self.conv_1 = nn.Conv2d(in_Channels=1, out_Channels=10, kernel_size=5)
# self.conv_2 = nn.Conv2d(in_Channels=88, out_Channels=20,
# kernel_size=5)
# self.inceptionA_1 = InceptionA(in_Channels=10)
# # self.inceptionA_2 = InceptionA(in_Channels=20)
#
# self.maxPool = nn.MaxPool2d(kernel_size=2)
# # self.fullConnect = nn.Linear(in_features=1408,
# # out_features=10)
#
# def forward(self, X_input):
# batchSize = X_input.size(0)
# # 第一层: 卷积
# x = self.conv_1(X_input) # 卷积
# x = self.maxPool(x) # 池化
# x = F.relu(x) # 激活
# # 第二层: InceptionA
# out = self.inceptionA_1(x)
# # # 第三层: 再卷积
# # x = self.conv_2(x)
# # x = self.maxPool(x)
# # x = F.relu(x)
# # # 第四层: 再InceptionA
# # x = self.inceptionA_2(x)
# # # 第五层,全连接层
# # x = x.view(batchSize, -1)
# # # 表示将(batch_size, channels, w, h)按照batch_size进行拉伸成shape=(batchSize, chanenls*w*h)
# # # eg: 原x.shape=(64, 2, 3, 4),调用 y =x.view(x.size(0), -1)后,y.shape = (64, 2*3*4)=(64, 24)
# # y_pred = self.fullConnect(x)
#
# return out
##################################################################################################

这段代码定义了一个名为InceptionA的类,它继承自torch.nn.Module。这个类实现了一个Inception模块,用于卷积神经网络中。

类中定义了两个方法:__init__forward__init__方法用于初始化对象,它接受两个参数in_Channelsout_Channels,分别表示输入通道数和输出通道数。方法首先定义了四个分支,每个分支都包含若干个卷积层和激活层。第一个分支包含一个池化层和一个1x1卷积层;第二个分支包含一个1x1卷积层;第三个分支包含一个1x1卷积层和一个5x5卷积层;第四个分支包含一个1x1卷积层和两个3x3卷积层。

forward方法用于前向传播,它接受一个参数X_input,表示输入数据。方法首先对输入数据进行池化操作,并使用第一个分支中的1x1卷积层对池化后的数据进行卷积操作。然后,使用第二、三、四个分支对输入数据进行卷积操作。最后,将四个分支的输出在通道维度上拼接在一起,并返回结果。

此外,代码中还有一些被注释掉的代码,它们定义了一个名为Net的类,用于整合模型。但是这些代码并未被使用。