当前位置:   article > 正文

SENet论文解读及代码实例

senet论文

SENet论文解读及代码实例

在SENet前的网络是针对卷积空间来做处理的,而SENet考虑了卷积通道上的的权重(明确地建模网络卷积特征通道之间的相互依赖关系),通过训练每个通道权重来抑制无用特征,提高有用特征在分类网络的占比,从而实现识别精度的提升。SENet引入权重计算网络,识别精度提升的代价为参数量提高10%左右,计算量提高1%左右。
1)SE block模块原理
下图为SE模块的建立过程 ,在SE模块中,生成的特征图经聚合层(Squeeze)生成每一个通道的全局信息,公式如下:
在这里插入图片描述

全局信息通过激励层生成每个通道的权值大小,每个通道再与权值相乘便可得到带权值的特征图。
在这里插入图片描述

在SE模块实际使用中,Squeeze层通过全局平均池化将全局空间信息压缩压缩到全局信息中, 可由下式表示:
在这里插入图片描述

为了利用全局信息来学习通道之间的权重,我们必须通过激励(Excitatio
-n)来获取权重,其中激励必须满足两个条件:必须能够学习通道之间的非线性相互作用;必须学习一种非互斥的关系,因为我们想要确保多个通道被允许被强调。 可用以下公式表示:
在这里插入图片描述

该结构由两个全连接层构成,这两个全连接层的作用就是融合各通道的feature map信息,第一个全连接层起降维作用,降维比取到16,激活函数采用Relu,第二个全连接将维数增加至原始输入维数,激活函数为sigmoid函数。
最后将 和 相乘得到权重
2)SE block模块使用
SE block可以嵌入各种卷积网络中使用,如Resnet、ResNeXt、Xception等,下图为SE block嵌入Resnet50的模块图:
在这里插入图片描述

SE-Resnet50在性能的变化:运算量从3.86GFlop增加至3.87GFlop,准确率从Resnet50提升至Resnet101的水平。模型结构如下:
在这里插入图片描述
代码实现SE-Resnet50

import torch.nn as nn
import torch.nn.functional as F
import math
from torchsummary import summary

class SElayer(nn.Module):
    def __init__(self,ratio,input_aisle):
        super(SElayer, self).__init__()
        self.pool=nn.AdaptiveAvgPool2d(1)
        self.fc=nn.Sequential(
            nn.Linear(input_aisle,input_aisle//ratio,bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(input_aisle//ratio,input_aisle,bias=False),
            nn.Sigmoid()
                             )
    def forward(self,x):
        a, b, _, _ = x.size()
        #读取批数据图片数量及通道数
        y = self.pool(x).view(a, b)
        #经池化后输出a*b的矩阵
        y = self.fc(y).view(a, b, 1, 1)
        #经全连接层输出【啊,吧,1,1】矩阵
        return x * y.expand_as(x)
        #输出权重乘以特征图
class SE_block(nn.Module):
    def __init__(self, outchannels, ratio=16, ):
        super(SE_block, self).__init__()
        self.backbone=nn.Sequential(nn.Conv2d(in_channels=outchannels, out_channels=outchannels // 4, kernel_size=1, stride=1),
                                    nn.BatchNorm2d(outchannels // 4),
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(in_channels=outchannels // 4, out_channels=outchannels // 4, kernel_size=3, stride=1, padding=1),
                                    nn.BatchNorm2d(outchannels // 4),
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(in_channels=outchannels // 4, out_channels=outchannels, kernel_size=1, stride=1),
                                    nn.BatchNorm2d(outchannels),
                                    nn.ReLU(inplace=True),
                                    )
        self.Selayer=SElayer(ratio, outchannels)
    def forward(self,x):
        residual=x
        x=self.backbone(x)
        x=self.Selayer(x)
        x=x+residual
        return x
class SE_Idenitity(nn.Module):
    def __init__(self, inchannel,outchannels, stride=2,ratio=16,):
        super(SE_Idenitity, self).__init__()
        self.backbone = nn.Sequential(
                                nn.Conv2d(in_channels=inchannel, out_channels=outchannels//4, kernel_size=1, stride=1),
                                nn.BatchNorm2d(outchannels//4),
                                nn.ReLU(inplace=True),
                                nn.Conv2d(in_channels=outchannels//4, out_channels=outchannels//4, kernel_size=3, stride=stride, padding=1),
                                nn.BatchNorm2d(outchannels//4),
                                nn.ReLU(inplace=True),
                                nn.Conv2d(in_channels=outchannels//4, out_channels=outchannels, kernel_size=1, stride=1),
                                nn.BatchNorm2d(outchannels),
                                nn.ReLU(inplace=True),
                                    )
        self.residual=nn.Conv2d(in_channels=inchannel, out_channels=outchannels, kernel_size=1, stride=stride)
        self.selayer = SElayer(ratio, outchannels)
    def forward(self,x):
        residual=self.residual(x)
        x=self.backbone(x)
        x=self.selayer(x)
        x=x+residual
        return x
class SE_Resnet(nn.Module):
    def __init__(self,layer_num,outchannel_num,num_class=10):
        super(SE_Resnet, self).__init__()
        self.initial=nn.Sequential(nn.Conv2d(in_channels=3,out_channels=64,kernel_size=7,padding=3,stride=2),
                                   nn.BatchNorm2d(64),
                                   nn.ReLU(inplace=True),
                                   nn.MaxPool2d(kernel_size=3,padding=1,stride=2))
        self.residual=self.make_layer(layer_num,outchannel_num)
        self.pool=nn.AdaptiveAvgPool2d(1)
        self.fc=nn.Linear(2048,num_class)
    def make_layer(self,number_layer,number_outchannel):
        layer_list=[]

        for i in range(len(number_layer)):
            if i==0:
                stride=1
            else:
                stride=2
            layer_list.append(SE_Idenitity(number_outchannel[i],number_outchannel[i+1],stride))
            for j in range(number_layer[i]-1):
                layer_list.append(SE_block(number_outchannel[i+1]))
        return nn.Sequential(*layer_list)
    def forward(self,x):
        x=self.initial(x)
        x=self.residual(x)
        x=self.pool(x)
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return F.softmax(x,dim=1)

def SE_Resnet50(num_class):
    model=SE_Resnet([3,4,6,3],[64,256,512,1024,2048],num_class)
    return model
def SE_Resnet101(num_class):
    model=SE_Resnet([3,4,23,3],[64,256,512,1024,2048],num_class)
    return model
def SE_Resnet151(num_class):
    model = SE_Resnet([3, 8, 36, 3], [64,256, 512, 1024, 2048], num_class)
    return model
device=torch.device("cuda:0")
Xception=SE_Resnet50(10).to(device)
summary(Xception,(3,224,224))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109

Resnet50与SE-Resnet50模型参数及计算量对比如下图:
1)SE-Resnet50参数:
SE-Resnet50
2)Resnet50参数:
在这里插入图片描述
整体大小由328M提高至417M,感觉比论文中说的10%要大上不少,运行时间上跑了一个epoch在我这吃土的MX150上多接近40%的时间。
总结:电脑差的话,SE-Resnet整体性价比不高!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/362706
推荐阅读
相关标签
  

闽ICP备14008679号