第四周学习 HybridSN,MobileNet V1,V2,V3,SENet

论文及视频学习

MobileNet V1

  • 以我的理解,MoblieNetV1的操作就是把普通的卷积分解为两步来做,第一步DW,第二部PW,就相当于把一个333的卷积分为 331的卷积+113的卷积操作。
  • 专注于移动端或嵌入式(轻量级)的网络,主要用来在不影响过多性能的情况下减少参数量
  • 亮点:
    • 提出了Depthwise Convolution
    • 增加了超参数α和β:控制参数倍速和
  • DW卷积
  • 深度可分的卷积:DW卷积、PW卷积
  • α:卷积核个数的倍率
  • β:卷积的层数
    在这里插入图片描述
    在这里插入图片描述

MobileNet V2

  • Inverted Residuals 倒残差结构
    • 结构相反
      • 和传统卷积比,这个先降维再升维
    • 更改了激活函数为 RELU6=min(max(x,0),6)
    • stride =1且输入输出特征矩阵shape相同时,才有shortcut连接
    • 扩展因子?
    • 也有α和β
      在这里插入图片描述

MobileNet V3

  • 更新block(benck)

    • 加入了SE模块:注意力机制:对每个chanel进行pooling处理
    • 激活函数的更新:NL:不同层的激活函数不同
    • 在这里插入图片描述
  • 使用NAS搜索参数

  • 重新设计耗时层结构

    • 减少第一个卷积层的卷积核个数
    • 精简Last Stage
      在这里插入图片描述

SENet

就是通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征。

  • Squeeze每个通道压成一个标量,一般可以用下采样
  • 再做一个Excitation操作,可以用Fc层来完成
  • 在乘到featuremap,作为这层的输出,传给下一层

Squeeze

  • 把一个通道压缩成一个标量,比如C×1×1的
  • 可以考虑全局的特征
    在这里插入图片描述

    这里面Global pooling是Squeeze 操作,后面是为了减少参数且获得更好的非线性参数

Excitation

通过参数为每个channel生成权重,这里两个FC和sigmoid就算Ex操作

代码

这里的代码就是用SENet的Basicblock替换了原有残差块ResNet18,主要就是在两层的卷积后,加入了

class BasicBlock(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        super(BasicBlock, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_channels)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_channels)

        # shortcut的输出维度和输出不一致时,用1*1的卷积来匹配维度
        self.shortcut = nn.Sequential()
        if stride != 1 or in_channels != out_channels:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                nn.BatchNorm2d(out_channels))

        # 在 excitation 的两个全连接
        self.fc1 = nn.Conv2d(out_channels, out_channels//16, kernel_size=1) 
        self.fc2 = nn.Conv2d(out_channels//16, out_channels, kernel_size=1)

    #定义网络结构
    def forward(self, x):
        #feature map进行两次卷积得到压缩
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))

        # Squeeze 操作:global average pooling
        w = F.avg_pool2d(out, out.size(2))
        
        # Excitation 操作: fc(压缩到16分之一)--Relu--fc(激到之前维度)--Sigmoid(保证输出为 0 至 1 之间)
        w = F.relu(self.fc1(w))
        w = F.sigmoid(self.fc2(w))

        # 重标定操作: 将卷积后的feature map与 w 相乘
        out = out * w 
        # 加上浅层特征图
        out += self.shortcut(x)
        #R elu激活
        out = F.relu(out)
        return out

这个代码的block基本就是下图结构,使用了Squeeze和Excitation,使得featuremap变为按权重调整后的样子。

在这里插入图片描述

对比下ResNet18,也就是未应用SE的模型,大概提高了2个百分点。
在这里插入图片描述

代码作业

论文

在这里插入图片描述


这篇论文主要介绍了一种新的model,使用3d卷积和2d卷积相结合处理高光谱图像分类问题。
网络的结构和参数图如下
在这里插入图片描述
作者做了一些实验,发现单纯的2d卷积网络或者3d卷积网络,效果都不是很好。最终找到了一个HybridSN模型效果最好,这种模型是把3d卷积和2d卷积混合在一起,主要是考虑了空间光谱和光谱的互补信息。
在这里插入图片描述
最终得到一个结论, HybridSN 模型基本上分别以 3D 和 2D 卷积的形式结合了空间光谱和光谱的互补信息,比当时最先进的方法在三个基准数据集上的实验结果都更好。且所提出的模型在计算效率上比 3D-CNN 模型更好,而且只需要少量数据就很好的结果。

代码

class HybridSN(nn.Module):
  def __init__(self):
    super(HybridSN, self).__init__()
    self.conv1 = nn.Sequential(
      nn.Conv3d( 1, 8, (7, 3, 3)),
      nn.BatchNorm3d(8))
    self.conv2 = nn.Sequential(
      nn.Conv3d( 8, 16, (5, 3, 3)),
      nn.BatchNorm3d(16))
    self.conv3 = nn.Sequential(
      nn.Conv3d( 16, 32, (3, 3, 3)),
      nn.BatchNorm3d(32))
    self.conv4 = nn.Sequential(
      nn.Conv2d( 576, 64, 3),
      nn.BatchNorm2d(64))
    self.fc1 = nn.Linear(in_features=18496, out_features=256)
    self.fc2 = nn.Linear(in_features=256, out_features=128)
    self.fc3 = nn.Linear(in_features=128, out_features=class_num)
    self.drop = nn.Dropout(p=0.4)

  def forward(self, x):
    x = F.relu(self.conv1(x))
    x = F.relu(self.conv2(x))
    x = F.relu(self.conv3(x))
    x = x.reshape(x.shape[0], -1, 19, 19)
    x = F.relu(self.conv4(x))
    x = x.reshape(x.shape[0],-1)
    x = F.relu(self.drop(self.fc1(x)))
    x = F.relu(self.drop(self.fc2(x)))
    x = self.fc3(x)

    return x

跑了100个epoch后,准确率大概在97.3%左右,但是每次的分类结果不一样。

在这里插入图片描述

思考题

  1. 思考3D卷积和2D卷积的区别

A:2d卷积对平面进行运算,而3D一般以空间的形式进行运算。这里面的3D卷积和2D卷积相比,多了一个深度通道,这个深度通道可以获取更多的信息,比如视频的连续帧和立体图像的分割等。比如使用VGG进行视频数据比较,3D版本明显好于2D版本3D卷积
在这里插入图片描述
我觉得这两张图可以很好的解释区别。
在这里插入图片描述
在这里插入图片描述

  1. 训练网络,然后多测试几次会发现每次分类的结果都不一样,请思考为什么?

由于fc层使用了dropout,会导致网络节点部分失活,每次的节点是随机的。
而使用了net.eval()代表测试时,batchNorm层,dropout层等用于优化训练而添加的网络层会被关闭,从而使得测试结果不会变化。

net.train()#训练前加
net.eval()#测试前加

在这里插入图片描述


可以看到加上之后,结果就一致了,且加上之后预测的结果也更好了。

在这里插入图片描述

  1. 如果想要进一步提升高光谱图像的分类性能,可以如何改进?
    我觉得可以利用SENet网络,把SENet模块添加到model中**

这里我去掉了SEnet模块中的残差结构和卷积层,只保留了SE部分,然后把SElayer加入了HybridSN的models里面,放在2d卷积的后面。

class SElayer(nn.Module):
    def __init__(self, in_channels, out_channels, stride=1):
        super(SElayer, self).__init__()
        

        # 在 excitation 的两个全连接
        self.fc1 = nn.Conv2d(out_channels, out_channels//16, kernel_size=1) 
        self.fc2 = nn.Conv2d(out_channels//16, out_channels, kernel_size=1)

    #定义网络结构
    def forward(self, x):

        # Squeeze 操作:global average pooling
        w = F.avg_pool2d(x,x.size(2))
        
        # Excitation 操作: fc(压缩到16分之一)--Relu--fc(激到之前维度)--Sigmoid(保证输出为 0 至 1 之间)
        w = F.relu(self.fc1(w))
        w = F.sigmoid(self.fc2(w))
        
        out = out * w 

        #R elu激活
        out = F.relu(out)
        return out

class HybridSN(nn.Module):
  def __init__(self):
    super(HybridSN, self).__init__()
    self.conv1 = nn.Sequential(
      nn.Conv3d( 1, 8, (7, 3, 3)),
      nn.BatchNorm3d(8))
    self.conv2 = nn.Sequential(
      nn.Conv3d( 8, 16, (5, 3, 3)),
      nn.BatchNorm3d(16))
    self.conv3 = nn.Sequential(
      nn.Conv3d( 16, 32, (3, 3, 3)),
      nn.BatchNorm3d(32))
    self.conv4 = nn.Sequential(
      nn.Conv2d( 576, 64, 3),
      nn.BatchNorm2d(64))
    self.SElayer = SElayer(64,64)
    self.fc1 = nn.Linear(in_features=18496, out_features=256)
    self.fc2 = nn.Linear(in_features=256, out_features=128)
    self.fc3 = nn.Linear(in_features=128, out_features=class_num)
    self.drop = nn.Dropout(p=0.4)    
  
  def forward(self, x):
    x = F.relu(self.conv1(x))
    x = F.relu(self.conv2(x))
    x = F.relu(self.conv3(x))
    x = x.reshape(x.shape[0], -1, 19, 19)
    x = F.relu(self.conv4(x))
    x = self.SElayer(x)
    x = x.reshape(x.shape[0],-1)
    x = F.relu(self.drop(self.fc1(x)))
    x = F.relu(self.drop(self.fc2(x)))
    x = self.fc3(x)

    return x

这是变换前后的结果

  1. 初始结果
  2. 加入net.eval()
    在这里插入图片描述
  3. 加入SE模块
    在这里插入图片描述

可以看到,初试的准确率是97.3%;加了一个net.eval()和net.train()后达到了98.33%,提升了1%;最后应用SElayer,准确率达到了98.62%,继续提高了0.3%;成功提升了高光谱图像的分类性能。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值