|
|
import torch.nn as nn
|
|
|
import torch
|
|
|
import torch
|
|
|
import torch.nn as nn
|
|
|
import torch.nn.functional as F
|
|
|
|
|
|
class SE_block(nn.Module):
|
|
|
def __init__(self, inchannel, ratio = 16):#压缩比默认16
|
|
|
super(SE_block, self).__init__()
|
|
|
#全局平均池化
|
|
|
self.gap = nn.AdaptiveAvgPool2d((1,1))
|
|
|
#两个全连接层
|
|
|
self.fc = nn.Sequential(
|
|
|
nn.Linear(inchannel, inchannel // ratio, bias = False),
|
|
|
nn.ReLU(),
|
|
|
nn.Linear(inchannel // ratio, inchannel, bias=False),
|
|
|
nn.Sigmoid()
|
|
|
)
|
|
|
|
|
|
def forward(self, x):
|
|
|
b ,c ,h ,w =x.size()#读取数据图片数量和通道数
|
|
|
#print(b, c, h, w) (32, 128, 27, 27)
|
|
|
y = self.gap(x).view(b ,c)#经过池化后输出b*c的矩阵
|
|
|
y =self.fc(y).view(b ,c, 1, 1)#经过全连接层输出(b,c,1,1)矩阵
|
|
|
|
|
|
return x * y.expand_as(x)#将得到的权重*原来的特征图x
|
|
|
|
|
|
|
|
|
class InceptionModule(nn.Module):
|
|
|
def __init__(self, in_channels, out_1x1, reduce_3x3, out_3x3, reduce_5x5, out_5x5, out_pool_proj):
|
|
|
super(InceptionModule, self).__init__()
|
|
|
|
|
|
#分支1:1*1卷积层
|
|
|
self.branch1 = nn.Sequential(
|
|
|
nn.Conv2d(in_channels, out_1x1, kernel_size=1),
|
|
|
nn.ReLU(True),
|
|
|
)
|
|
|
|
|
|
#分支2:1*1卷积层 3*3卷积层
|
|
|
self.branch2 = nn.Sequential(
|
|
|
nn.Conv2d(in_channels, reduce_3x3, kernel_size=1),
|
|
|
nn.ReLU(True),
|
|
|
nn.Conv2d(reduce_3x3, out_3x3, kernel_size=3, padding=1),
|
|
|
nn.ReLU(True),
|
|
|
)
|
|
|
|
|
|
#分支3:1*1卷积层 5*5卷积层
|
|
|
self.branch3 = nn.Sequential(
|
|
|
nn.Conv2d(in_channels, reduce_5x5, kernel_size=1),
|
|
|
nn.ReLU(True),
|
|
|
nn.Conv2d(reduce_5x5, out_5x5, kernel_size=5, padding=2),
|
|
|
nn.ReLU(True),
|
|
|
)
|
|
|
|
|
|
#分支4:3*3最大池化层 1*1卷积层
|
|
|
self.branch4 = nn.Sequential(
|
|
|
nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
|
|
|
nn.Conv2d(in_channels, out_pool_proj, kernel_size=1),
|
|
|
nn.ReLU(True),
|
|
|
)
|
|
|
|
|
|
#进行concatenate连接,将四个分支合并一起作为输出
|
|
|
def forward(self, x):
|
|
|
outputs = [self.branch1(x), self.branch2(x), self.branch3(x), self.branch4(x)]
|
|
|
return torch.cat(outputs, 1)
|
|
|
|
|
|
|
|
|
class ImprovedAlexNet(nn.Module):
|
|
|
def __init__(self, num_classes=1000):
|
|
|
super(ImprovedAlexNet, self).__init__()
|
|
|
self.features = nn.Sequential(
|
|
|
nn.Conv2d(3, 64, kernel_size=11, stride=4, padding=2),#卷积层1
|
|
|
nn.ReLU(inplace=True),#激活函数
|
|
|
nn.MaxPool2d(kernel_size=3, stride=2),#最大池化层1
|
|
|
SE_block(64),
|
|
|
InceptionModule(64, 32, 48, 64, 8, 16, 16), # 替代原始的第一个卷积层
|
|
|
nn.MaxPool2d(kernel_size=3, stride=2),#最大池化层2
|
|
|
#SE_block(128),
|
|
|
InceptionModule(128, 64, 96, 128, 16, 32, 32), # 替代原始的第二个卷积层
|
|
|
nn.MaxPool2d(kernel_size=3, stride=2),#最大池化层3
|
|
|
)
|
|
|
self.classifier = nn.Sequential(
|
|
|
nn.Dropout(p=0.5),#Dropout层,表示对输入数据进行随机丢弃操作,丢弃概率为0.5,用于防止过拟合
|
|
|
nn.Linear(256 * 6 * 6, 2048),#全连接层,将输入特征的维度由(256,6,6)转换为2048,用于进行线性变换操作
|
|
|
#nn.Linear(128 * 13 * 13, 2048),
|
|
|
nn.ReLU(inplace=True),#激活函数
|
|
|
nn.Dropout(p=0.5),#Dropout层,作用同上
|
|
|
nn.Linear(2048, 2048),#全连接层
|
|
|
nn.ReLU(inplace=True),#激活函数
|
|
|
nn.Linear(2048, num_classes),#全连接层
|
|
|
)
|
|
|
|
|
|
def forward(self, x):
|
|
|
x = self.features(x)#进行卷积操作
|
|
|
#print(x.shape)
|
|
|
x = torch.flatten(x, start_dim=1)#展平
|
|
|
x = self.classifier(x)#输出
|
|
|
return x
|
|
|
|