MobileNet

传统卷积神经网络,内存需求大、运算量大导致无法在移动设备及嵌入式设备上运行。

MobileNet网络是由google团队在2017年提出的,专注于移动端或者嵌入式设备中的轻量级CNN网络。相比于传统神经网络,在准确率小幅降低的前提下大大减少模型参数与运算量

网络中的亮点: Depthwise Convolution(大大减少运算量和参数数量); 增加超参数α(控制卷积层卷积核个数),β(控制输入图像大小)。

DW卷积后特征矩阵的深度不会发生变化。

 深度可分的卷积操作(Depth Separeable Conv) :DW + PW 

深度可分卷积和普通卷积计算量对比

MobileNet V1网络

MobileNet V1网络相比VGG16准确率减少了0.9%,但模型参数只有VGG的1/32;α指卷积核倍率,卷积核个数减少时准确率略降低,但计算量大大减少;β指分辨率,适当减小输入图像大小可以在保证准确率小幅降低的前提下大幅降低运算量。

实际使用中发现,DW卷积的卷积核容易不起作用。

MobileNet V2网络

 MobileNet V2网络相对于MobileNet V1网络准确率更高,模型更小。

网络亮点:Inverted Residuals(倒残差结构);Linear Bottlenecks。

Inverted residual block 

 倒残差结构采用的是ReLU6激活函数,是ReLU的改进版。RLU激活函数对低维特征信息造成大量损失

 倒残差结构

 MobileNet V3网络

MobileNet V3网络相对于MobileNet V2网络更准确,更高效。

网络亮点:更新了block(bneck);使用NAS搜索参数(Neural Architecture Search);重新设计耗时层结构。

 第一个全连接层的节点个数是特征矩阵channel的1/4,第二个全连接层的节点个数和特征矩阵channel一致。

 减少第一个卷积层的卷积核个数减少了2ms,精简Last Stage减少了7ms,占11%。

 swish激活函数计算、求导复杂,对量化过程不友好

h-swish = x * h-sigmoid

 网络结构

SE-Net

网络可以从特征通道之间的关系来考虑去提升性能,基于这一点提出了Squeeze-and-Excitation Networks(简称SENet)。SE-Net采用了一种全新的“特征重标定”策略,就是通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征。

SE 模块

 给定一个输入,其特征通道数为,通过一系列卷积等一般变换后得到一个特征通道数为的特征。接下来通过三个操作来重标定前面得到的特征。

  • Squeeze 操作。顺着空间维度来进行特征压缩,将每个二维的特征通道变成一个实数,这个实数某种程度上具有全局的感受野,并且输出的维度和输入的特征通道数相匹配。它表征着在特征通道上响应的全局分布,而且使得靠近输入的层也可以获得全局的感受野。
  • Excitation 操作。是一个类似于循环神经网络中门的机制。通过参数来为每个特征通道生成权重,其中参数被学习用来显式地建模特征通道间的相关性。
  • Reweight操作。将Excitation的输出的权重看做是进过特征选择后的每个特征通道的重要性,然后通过乘法逐通道加权到先前的特征上,完成在通道维度上的对原始特征的重标定。

上左图是将SE模块嵌入到Inception结构的一个示例。方框旁边的维度信息代表该层的输出。使用global average pooling 作为Squeeze 操作,两个Fully Connected 层组成一个Bottleneck结构去建模通道间的相关性,并输出和输入特征同样数目的权重 。首先将特征维度降低到输入的1/16 ,然后经过ReLU激活后再通过一个Fully Connected 层升回到原来的维度,这样做比直接用一个Fully Connected 层的好处在于:1)具有更多的非线性,可以更好地拟合通道间复杂的相关性;2)极大地减少了参数量和计算量。然后通过一个Sigmoid的门获得0~1之间归一化的权重,最后通过一个Scale的操作来将归一化后的权重加权到每个通道的特征上。

上右图是将SE 嵌入到ResNet模块中的一个例子,操作过程基本和SE-Inception一样,只不过是在Addition前对分支上Residual的特征进行了特征重标定。如果对Addition后主支上的特征进行重标定,由于在主干上存在0~1的scale操作,在网络较深BP优化时就会在靠近输入层容易出现梯度消散的情况,导致模型难以优化。

在训练中使用了一些常见的数据增强方法和Li Shen提出的均衡数据策略。为了提高训练效率使用了自己优化的分布式训练系统ROCS, 并采用了更大的batch-size 和初始学习率。

在ImageNet数据集上进行实验,并从两个方面来进行论证。一个是性能的增益vs. 网络的深度; 另一个是将SE嵌入到现有的不同网络中进行结果对比。

网络的深度对SE的影响

 从上表可以看出,SE-ResNets 在各种深度上都远远超过了其对应的没有SE的结构版本的精度,这说明无论网络的深度如何,SE模块都能够给网络带来性能上的增益。值得一提的是,SE-ResNet-50 可以达到和ResNet-101 一样的精度;更甚,SE-ResNet-101 远远地超过了更深的ResNet-152。

上图展示了ResNet-50 和 ResNet-152 以及它们对应的嵌入SE模块的网络在ImageNet上的训练过程,可以明显地看出加入了SE模块的网络收敛到更低的错误率上。

从上表可以看出,将SE模块嵌入到ResNeXt、BN-Inception、Inception-ResNet-v2上均获得了不菲的增益效果。由此看出,SE的增益效果不仅仅局限于某些特殊的网络结构,它具有很强的泛化性。

BasicBlock

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) 
        # 第一个全连接层将特征维度降低到输入的1/16
        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)
        #ReLU激活
        out = F.relu(out)
        return out

SENet 网络

#创建SENet网络
class SENet(nn.Module):
    def __init__(self):
        super(SENet, self).__init__()
        #最终分类的种类数
        self.num_classes = 10
        #输入深度为64
        self.in_channels = 64

        #先使用64*3*3的卷积核
        self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
        self.bn1 = nn.BatchNorm2d(64)
        #卷积层的设置,BasicBlock
        #2,2,2,2为每个卷积层需要的block块数
        self.layer1 = self._make_layer(BasicBlock,  64, 2, stride=1)
        self.layer2 = self._make_layer(BasicBlock, 128, 2, stride=2)
        self.layer3 = self._make_layer(BasicBlock, 256, 2, stride=2)
        self.layer4 = self._make_layer(BasicBlock, 512, 2, stride=2)
        #全连接
        self.linear = nn.Linear(512, self.num_classes)

    #实现每一层卷积
    #blocks为大layer中的残差块数
    #定义每一个layer有几个残差块,resnet18是2,2,2,2
    def _make_layer(self, block, out_channels, blocks, stride):
        strides = [stride] + [1]*(blocks-1)
        layers = []
        for stride in strides:
            layers.append(block(self.in_channels, out_channels, stride))
            self.in_channels = out_channels
        return nn.Sequential(*layers)

    #定义网络结构
    def forward(self, x):
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.layer1(out)
        out = self.layer2(out)
        out = self.layer3(out)
        out = self.layer4(out)
        out = F.avg_pool2d(out, 4)
        out = out.view(out.size(0), -1)
        out = self.linear(out)
        return out

HybridSN

HybridSN模型

 网络结构

 3D卷积相比于2D卷积多一个维度,对应的激活函数也多一个维度。2D conv的卷积核是(c, k_h, k_w),卷积核在输入图像上的的空间维度(即(height, width)两维)上进行进行滑窗操作;3D conv的卷积核是(c, k_d, k_h, k_w),其中k_d就是多出来的第三维,根据具体应用,在视频中就是时间维,在CT图像中就是层数维,卷积核在输入3D图像的空间维度(height和width维)和depth维度上均进行滑窗操作。

它们适用的场景不同,容易减少数据集的维度,但不容易增加数据集维度,所以应当先进行高维的卷积。

HybridSN网络部分

class_num = 16

class HybridSN(nn.Module):
  def __init__(self, num_classes=16):
    super(HybridSN, self).__init__()
    # conv1:(1, 30, 25, 25), 8个 7x3x3 的卷积核 ==>(8, 24, 23, 23)
    self.conv1 = nn.Conv3d(in_channels=1, out_channels = 8, kernel_size=(7, 3, 3))
    # conv2:(8, 24, 23, 23), 16个 5x3x3 的卷积核 ==>(16, 20, 21, 21)
    self.conv2 = nn.Conv3d(in_channels=8, out_channels = 16, kernel_size=(5, 3, 3))
    # conv3:(16, 20, 21, 21),32个 3x3x3 的卷积核 ==>(32, 18, 19, 19)
    self.conv3 = nn.Conv3d(in_channels=16, out_channels = 32, kernel_size=(3, 3, 3))
    # conv3_2d (576, 19, 19),64个 3x3 的卷积核 ==>((64, 17, 17)
    self.conv3_2d = nn.Conv2d(in_channels=576, out_channels = 64, kernel_size=(3,3))
    # 全连接层(256个节点)
    self.dense1 =  nn.Linear(18496,256)
    # 全连接层(128个节点)
    self.dense2 =  nn.Linear(256,128)
    # 最终输出层(16个节点)
    self.out = nn.Linear(128, num_classes)
    #  Dropout(0.4)
    self.drop = nn.Dropout(p=0.4)
    # 激活函数ReLU
    self.relu = nn.ReLU()

  def forward(self, x):
    out = self.relu(self.conv1(x))
    out = self.relu(self.conv2(out))
    out = self.relu(self.conv3(out))
    # 进行二维卷积,把前面的 32*18 reshape 一下,由(32, 18, 19, 19)得到 (576, 19, 19)
    out = out.view(-1, out.shape[1] * out.shape[2], out.shape[3], out.shape[4])
    out = self.relu(self.conv3_2d(out))
    # flatten 操作,变为 18496 维的向量,
    out = out.view(out.size(0), -1)
    out = self.dense1(out)
    out = self.drop(out)
    out = self.dense2(out)
    out = self.drop(out)
    out = self.out(out)
    return out

每次测试分类的结果都不一样。

      

     

 高光谱图分类结果

 

思考

  • 为什么会每次分类的结果都不一样?

启用dropout后会进行随机采样,导致网络在测试时分类结果不一样,准确率受到影响。

  • 如果想要进一步提升高光谱图像的分类性能,可以如何改进?

 使用自注意力机制可以提升网络的性能。

注意力机制

对输入数据本身作一些处理,得到一个权重,这个权重可以帮助进行更准确的分类。 

	#attention
    self.sa1 = nn.Conv2d(64, 64//rate, kernel_size=1)
    self.sa2 = nn.Conv2d(64//rate, 64, kernel_size=1)
	weight = F.relu(self.sa1(weight))
    weight = F.sigmoid(self.sa2(weight))
    out = out * weight

 本质上,对于每个输入向量,Self-Attention产生一个向量,该向量在其邻近向量上加权求和,其中权重由输入之间的关系或连通性决定。它强调重要特征,抑制噪声。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值