目录

原网络结构1.空间滤波2.特征提取3.分类和定位

改变特征提取模块中网络结构1.使用ResNet-50网络加入FPN提取多尺度特征2.增加CBAM自注意力机制

原网络结构

某"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

接下来就是将CBAM模块加入到改进后的网络中了,在这里我在网络最后的卷积后添加了CBAM模块,在这里为了保持原有网络结构的某些特征,我保留了原来DOSED网络中的两个卷积块,在这之后添加了CBAM。

查看原文