原网络结构
某"D网络"是用来进行睡眠微事件检测的深度学习模型。但是我发现该网络的性能并非十分完善;正如论文中所述的那样,在SSC、WSC睡眠数据集上对于纺锤波、K复合波等睡眠微事件的检测性能方面(包括precision、recall、F1-score)有待提高。
为此鄙人不才,希望能够改进该网络的结构,从而提高模型对睡眠微事件检测的性能。
下面是对该网络模型的简单描述。
1.空间滤波
空间滤波是由一个简单的二维卷积和转置操作组成的,这个做法通过使用卷积来对输入的信号进行线性的空间滤波操作,从而增加输入信号的信噪比。(但是我发现,在源码中真的只是用一个简单的卷积操作 ┭┮﹏┭┮)
真的很简单的卷积结构!!!
nn.Conv2d(
in_channels=1,
out_channels=self.number_of_channels,
kernel_size=(self.number_of_channels, 1),
stride=1,
padding=0)
2.特征提取
这个特征提取模块,也是我改进非常大的地方,因为我发现在作者提供的网络源代码中,只是用k个简单的卷积block组成(我想说仅仅通过卷积层、batchnorm、relu和maxpool真的能有好的性能么 ,ԾㅂԾ,)
这是该模块的大致结构,可以看见由k个包含二维卷积层的块组成。
nn.Sequential(
OrderedDict([
("conv_{}".format(k), nn.Conv2d(
in_channels=4 * (2 ** (k - 1)) if k > 1 else 1,
out_channels=4 * (2 ** k),
kernel_size=(1, 3),
padding=(0, 1),
stride=1
)),
# ("cbam_{}".format(k),cbam(in_channel=4 * (2 ** k))),
("batchnorm_{}".format(k), nn.BatchNorm2d(4 * (2 ** k))),
("relu_{}".format(k), nn.ReLU()),
("max_pooling_{}".format(k), nn.MaxPool2d(kernel_size=(1, 2),stride=(1,2))),
])
) for k in range(1, self.k_max-1)
3.分类和定位
分类和定位模块也是通过卷积层实现的。【这里就不过多描述了 O(∩_∩)O】
改变特征提取模块中网络结构
这里只是简单的给网路进行改进,结合Yolov5当中FPN特征金字塔,并添加相应的CBAM注意力机制,希望能够使得网络的性能增强些。(目前新增结构正在训练验证中…)
1.使用ResNet-50网络加入FPN提取多尺度特征
特征金字塔设计的思路是因为,对于图像特征来说,底层具有较强的定位特征,而顶层具有较强的语义特征,那么就需要结合多尺度的特征来将高维和低维的特征进行融合。
从上图FPN的结构中可以很好的进行观察,随着左半部分网络的加深,会使得语义信息更加得丰富。同时通过上采样的方法,不断放大特征图,能够使得低层特征也有丰富的语义信息。
在上述结构当中,是将上采样的结果和自底向上生成的特征图进行融合。从左侧过来的特征图,需要先通过1x1的卷积进行通道的改变;然后和自顶向下而来的特征图进行add,之后还需要经过一个3x3的卷积(这里通过3x3的卷积是消除上采样产生的混叠效应,因为上采样和原图叠加后会造成特征的不连续,在原来特征图上失真,在灰度变化的地方可能出现明显的锯齿状)
在这,我是在ResNet-50的网络中添加FPN(FPN结构的部分代码):
self.layer1 = nn.Sequential(*layers[:5])
self.layer2 = nn.Sequential(*layers[5])
self.layer3 = nn.Sequential(*layers[6])
self.layer4 = nn.Sequential(*layers[7])
# 使用1x1卷积进行侧向连接
self.lateral5 = nn.Conv2d(in_channels=2048,out_channels=256,kernel_size=1)
self.lateral4 = nn.Conv2d(in_channels=1024, out_channels=256, kernel_size=1)
self.lateral3 = nn.Conv2d(in_channels=512, out_channels=256, kernel_size=1)
self.lateral2 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1)
# 进行上采样
self.upsample2 = nn.ConvTranspose2d(in_channels=256, out_channels=256, kernel_size=4, stride=2, padding=1)
self.upsample3 = nn.ConvTranspose2d(in_channels=256, out_channels=256, kernel_size=4, stride=2, padding=1)
self.upsample4 = nn.ConvTranspose2d(in_channels=256,out_channels=256, kernel_size=4, stride=2, padding=1)
# 使用3x3的卷积,为了消除上采样产生的混叠效应
self.smooth2 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1)
self.smooth3 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1)
self.smooth4 = nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1)
然后将该模块加入到对应的网络当中。(ps:在这之前,需要将在该模块之前通过一个1x1的卷积层,用来改变通道数,从而能够符合该模块的输入通道。)
p2,p3,p4,p5 = self.fpn(self.conv1(x))
最终得到的p2,p3,p4,p5即为经过FPN后得到的多尺度特征图,接下来可以进行后续操作。
2.增加CBAM自注意力机制
在网络中添加注意力机制,可以提升网络的检测性能,在改进的网络中,我添加的是CBAM注意力机制。
CBAM注意力机制有两个模块,包括通道注意力机制和空间注意力机制。通过在通道和空间两个维度的分析,实现从通道到空间的注意力结构。
1.通道注意力机制
以上图能够很好的将通道注意力机制的结构展现。通道注意力机制先将特征图进行全局最大池化和平均池化,从而获得两张不同维度的特征图(进行相应的转化:[b,c,h,w]==>[b,c,1,1],可以看到后面两个维度都变成1,可以看成在通道维的操作);然后通过一个公用的多层感知机网络,在这里需要使用1x1的卷积来改变通道数;将两个特征图在通道维度进行堆叠,最后通过激活函数进行权重归一化。
在这里展示通道注意力机制的部分代码:
class ChannelAttentionModule(nn.Module):
def __init__(self, channel, ratio=4):
super(ChannelAttentionModule, self).__init__()
# 全局平均池化
self.avg_pool = nn.AdaptiveAvgPool2d(1)
# 全局最大池化
self.max_pool = nn.AdaptiveMaxPool2d(1)
# 公用的多层感知机网络
self.shared_MLP = nn.Sequential(
# 使用1x1卷积作为全连接层
nn.Conv2d(channel, channel // ratio, 1, bias=False),
nn.ReLU(),
nn.Conv2d(channel // ratio, channel, 1, bias=False)
)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
avgout = self.shared_MLP(self.avg_pool(x))
maxout = self.shared_MLP(self.max_pool(x))
# 将两张图在通道维度进行堆叠
return self.sigmoid(avgout + maxout)
2.空间注意力机制
在这里,是要对之前通道注意力机制输出的特征图进行空间域方向的处理,可以看成将通道维度视为1,然后观察其他维。
首先需要对特征图进行最大池化和平均池化操作;然后将这两个特征图在通道维度进行concat;使用7x7或3x3(在这里我用的是7x7)的卷积融合通道信息;再经过激活函数对空间权重归一化。
空间注意力机制的代码如下所示:
# 空间注意力机制
class SpatialAttentionModule(nn.Module):
def __init__(self):
super(SpatialAttentionModule, self).__init__()
self.conv2d = nn.Conv2d(in_channels=2, out_channels=1, kernel_size=7, stride=1, padding=3)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
# 平均池化
avgout = torch.mean(x, dim=1, keepdim=True)
# 最大池化
maxout, _ = torch.max(x, dim=1, keepdim=True)
# 将两张特征图在通道维度进行concat
out = torch.cat([avgout, maxout], dim=1)
out = self.sigmoid(self.conv2d(out))
return out
ps:注意,以上需要将特征图和权重相乘,我都将此操作放到最后构造CBAM的forward()函数当中了 O(∩_∩)O文章来源:https://www.toymoban.com/news/detail-492826.html
接下来就是将CBAM模块加入到改进后的网络中了,在这里我在网络最后的卷积后添加了CBAM模块,在这里为了保持原有网络结构的某些特征,我保留了原来DOSED网络中的两个卷积块,在这之后添加了CBAM。文章来源地址https://www.toymoban.com/news/detail-492826.html
到了这里,关于在网络中添加特征金字塔,和自注意力机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!