- 本文为365天深度学习训练营 中的学习记录博客
- 原作者:K同学啊
- 在DenseNet系列算法中插入SE-Net通道注意力机制,并完成猴痘病识别
- 改进思路是否可以迁移到其他地方
- 测试集accuracy到达89%(拔高)
- 语言环境:python 3.8
- 编译器:Jupyter notebook
- 深度学习环境:Pytorch
- torch==2.4.0+cu124
- torchvision==0.19.0+cu124
SE-Net 是 ImageNet 2017(ImageNet 收官赛)的冠军模型,是由WMW团队发布。具有复杂度低,参数少和计算量小的优点。且SENet 思路很简单,很容易扩展到已有网络结构如 Inception 和 ResNet 中。
已经有很多工作在空间维度上来提升网络的性能,如 Inception 等,而 SENet 将关注点放在了特征通道之间的关系上。其具体策略为:通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征,这又叫做“特征重标定”策略。具体的 SE 模块如下图所示:
SE-NET 的核心思想是通过 Squeeze-and-Excitation(SE)模块的机制来增强网络的表示能力。具体来说,SE模块对每一个卷积层的特征图进行重新标定,通过显式建模通道之间的相互依赖关系来提升网络的表现力。以下是SE模块的两个主要步骤:
SE模块的灵活性在于它可以直接应用现有的网络结构中。以 Inception 和 ResNet 为例,我们只需要在 Inception 模块或 Residual 模块后添加一个 SE 模块即可。具体如下图所示:
上图分别是将 SE 模块嵌入到 Inception 结构与 ResNet 中的示例,方框旁边的维度信息代表该层的输出,c 表示 Excitation 操作中的降维系数。
设置GPU、导入数据、划分数据集等步骤同前。
import torch.nn.functional as F
from collections import OrderedDict
class DenseLayer(nn.Sequential):
def __init__(self,in_channel,growth_rate,bn_size,drop_rate):
super(DenseLayer,self).__init__()
self.add_module('norm1',nn.BatchNorm2d(in_channel))
self.add_module('relu1',nn.ReLU(inplace=True))
self.add_module('conv1',nn.Conv2d(in_channel,bn_size*growth_rate,kernel_size=1,stride=1))
self.add_module('norm2',nn.BatchNorm2d(bn_size*growth_rate))
self.add_module('relu2',nn.ReLU(inplace=True))
self.add_module('conv2',nn.Conv2d(bn_size*growth_rate,growth_rate,kernel_size=3,stride=1,padding=1))
self.drop_rate = drop_rate
def forward(self,x):
new_feature = super(DenseLayer,self).forward(x)
if self.drop_rate > 0:
new_feature = F.dropout(new_feature,p=self.drop_rate,training=self.training)
return torch.cat([x,new_feature],1)
class DenseBlock(nn.Sequential):
def __init__(self,num_layers,in_channel,bn_size,growth_rate,drop_rate):
super(DenseBlock,self).__init__()
for i in range(num_layers):
layer = DenseLayer(in_channel+i*growth_rate,growth_rate,bn_size,drop_rate)
self.add_module('denselayer%d'%(i+1,),layer)
class Transition(nn.Sequential):
def __init__(self,in_channel,out_channel):
super(Transition,self).__init__()
self.add_module('norm',nn.BatchNorm2d(in_channel))
self.add_module('relu',nn.ReLU(inplace=True))
self.add_module('conv',nn.Conv2d(in_channel,out_channel,kernel_size=1,stride=1))
self.add_module('pool',nn.AvgPool2d(kernel_size=2,stride=2))
class SELayer(nn.Module):
def __init__(self,<