|从零搭建网络| EfficientNet网络详解及搭建

🌜|从零搭建网络| EfficientNet系列网络详解及搭建🌛

🌜 前言 🌛

   轻量级网络整理的也差不多了,应该还剩下这一个EfficientNet没出,这篇博客就用来对EfficientNet网络进行一个网络详解和搭建讲解,同时本篇博客也会从pytorch的框架下复现EfficientNet网络。

🌜 EfficientNet详解 🌛

   首先附上原论文地址:https://arxiv.org/pdf/1905.11946.pdf
在这里插入图片描述
   本篇博客除了给出一个新的轻量级网络的搭建结构之外,还主要介绍了网络的各个属性对于网络准确率,计算速度等的影响以及怎样改进的方法。事实证明,EfficientNet网络在ImageNet的准确率和参数量方面对于当时期的各大模型都遥遥领先。
在这里插入图片描述
   可以看出在当时期的网络中,EfficientNet在ImageNet top-1的准确率达到了一个新高。并且正如本篇论文摘要中叙述的,他是当时时期唯一一个同时探索分辨率、网络深度以及宽度的影响。

🌜 EfficientNet创新点 🌛

   本篇论文除了做了一个新的网络结构之外,极大篇幅都用来叙述 分辨率、网络深度以及宽度对于网络评估结果的影响 ,这篇博客简单对其做一个叙述,感兴趣的话可以到原论文中查看,主要对于网络搭建部分详细解释。
在这里插入图片描述
   如上图所示,a图表示一个基准网络、b图表示增加卷积核个数,增大输出特征的通道数、c图表示对网络结构进行堆叠,加深网络深度、d图表示对图像的分辨率进行增加,e图指的是同时增加输出特征通道数、网络深度以及输入图像的分辨率。
在这里插入图片描述

   上图是增加各部分指标对于准确率的影响。首先我们根据以往的经验,增加网络的深度能够得到更加丰富的特征并且能够很好地应用到其他的任务中,但是过深的网络会面临梯度消失,训练困难等问题;增加网络宽度能够获得更高细粒度的特征并且也更容易训练,但对于宽度很大而且深度较浅的网络往往很难学习到较为复杂的特征;增加图像的分辨率能够潜在的获得更高细粒度的特征模板,但对于非常高的输入分辨率,准确率的增益也会减小,并且较大的分辨率也会增大训练的难度。

🌜 一维EfficientNet搭建详解 🌛

   EfficientNet的搭建也并没有很难得点,首先看一下整体结构。
在这里插入图片描述
   这里的MBConv指的是MobileNetV3block结构,那么首先就来简单回顾一下这个block结构。(这里就不过多赘述,想要详细了解可以移步:|从零搭建网络| MobileNet系列网络详解及搭建
在这里插入图片描述
   这里和MobileNetV3中唯一不同的点就是在捷径分支前面加了个Dropout层,中间深度可分离卷积卷积核由EfficientNet中的结构图定义。下面直接看相关block的搭建:

import torch

class SE_block(torch.nn.Module):
    def __init__(self,inchannel,ratio = 4):
        super().__init__()
        self.pool = torch.nn.AdaptiveAvgPool1d(1)
        self.conv = torch.nn.Sequential(
            torch.nn.Linear(inchannel,inchannel // ratio),
            torch.nn.ReLU(),
            torch.nn.Linear(inchannel // ratio,inchannel),
            torch.nn.Hardsigmoid(inplace=True)
        )

    def forward(self,input):
        b,c,_ = input.size()
        x = self.pool(input)
        x = x.view([b,c])
        x = self.conv(x)
        x = x.view([b,c,1])
        return x*input

class MB_block(torch.nn.Module):
    def __init__(self,input_channels,outchannel,kernal,stride,expand_ratio):
        super().__init__()
        self.input_channels = input_channels
        self.outchannel = outchannel
        self.stride = stride
        self.conv = torch.nn.Sequential(
            torch.nn.Conv1d(input_channels,input_channels*expand_ratio,1),
            torch.nn.BatchNorm1d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            torch.nn.Conv1d(input_channels*expand_ratio,input_channels*expand_ratio,kernal,stride,padding=kernal // 2,groups=input_channels*expand_ratio),
            torch.nn.BatchNorm1d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            SE_block(input_channels*expand_ratio),
            torch.nn.Conv1d(input_channels*expand_ratio,outchannel,1,1),
            torch.nn.BatchNorm1d(outchannel)
        )
    def forward(self,x):
        out = self.conv(x)
        if self.stride == 1 and self.input_channels == self.outchannel:
            out += x
        return out

   代码中SE_block为定义的注意力机制。
   下面只需要根据结构图一步步堆叠MBConv即可,下面是搭建网络的代码:

class EfficientNet(torch.nn.Module):
    def __init__(self,input_channels,classes):
        super().__init__()
        self.input_channels = input_channels
        self.classes = classes
        self.stage_1 = torch.nn.Sequential(
            torch.nn.Conv1d(input_channels,32,3,2,1),
            torch.nn.BatchNorm1d(32),
            torch.nn.Hardswish()
        )
        self.stage_2 = torch.nn.Sequential(
            MB_block(32,16,3,1,1)
        )
        self.stage_3 = torch.nn.Sequential(
            MB_block(16,24,3,2,6),
            MB_block(24,24,3,1,6)
        )
        self.stage_4 = torch.nn.Sequential(
            MB_block(24,40,5,2,6),
            MB_block(40,40,5,1,6)
        )
        self.stage_5 = torch.nn.Sequential(
            MB_block(40,80,3,2,6),
            MB_block(80,80,3,1,6),
            MB_block(80,80,3,1,6),
        )
        self.stage_6 = torch.nn.Sequential(
            MB_block(80,112,5,1,6),
            MB_block(112,112,5,1,6),
            MB_block(112,112,5,1,6),
        )
        self.stage_7 = torch.nn.Sequential(
            MB_block(112,192,5,2,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
        )
        self.stage_8 = torch.nn.Sequential(
            MB_block(192,320,3,1,6)
        )
        self.stage_9 = torch.nn.Sequential(
            torch.nn.Conv1d(320,1280,1),
            torch.nn.AdaptiveAvgPool1d(1),
            torch.nn.Flatten(),
            torch.nn.Linear(1280,classes)
        )
    def forward(self,x):
        x = self.stage_1(x)
        x = self.stage_2(x)
        x = self.stage_3(x)
        x = self.stage_4(x)
        x = self.stage_5(x)
        x = self.stage_6(x)
        x = self.stage_7(x)
        x = self.stage_8(x)
        x = self.stage_9(x)
        return x

   下面是完整代码:

import torch

class SE_block(torch.nn.Module):
    def __init__(self,inchannel,ratio = 4):
        super().__init__()
        self.pool = torch.nn.AdaptiveAvgPool1d(1)
        self.conv = torch.nn.Sequential(
            torch.nn.Linear(inchannel,inchannel // ratio),
            torch.nn.ReLU(),
            torch.nn.Linear(inchannel // ratio,inchannel),
            torch.nn.Hardsigmoid(inplace=True)
        )

    def forward(self,input):
        b,c,_ = input.size()
        x = self.pool(input)
        x = x.view([b,c])
        x = self.conv(x)
        x = x.view([b,c,1])
        return x*input

class MB_block(torch.nn.Module):
    def __init__(self,input_channels,outchannel,kernal,stride,expand_ratio):
        super().__init__()
        self.input_channels = input_channels
        self.outchannel = outchannel
        self.stride = stride
        self.conv = torch.nn.Sequential(
            torch.nn.Conv1d(input_channels,input_channels*expand_ratio,1),
            torch.nn.BatchNorm1d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            torch.nn.Conv1d(input_channels*expand_ratio,input_channels*expand_ratio,kernal,stride,padding=kernal // 2,groups=input_channels*expand_ratio),
            torch.nn.BatchNorm1d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            SE_block(input_channels*expand_ratio),
            torch.nn.Conv1d(input_channels*expand_ratio,outchannel,1,1),
            torch.nn.BatchNorm1d(outchannel)
        )
    def forward(self,x):
        out = self.conv(x)
        if self.stride == 1 and self.input_channels == self.outchannel:
            out += x
        return out

class EfficientNet(torch.nn.Module):
    def __init__(self,input_channels,classes):
        super().__init__()
        self.input_channels = input_channels
        self.classes = classes
        self.stage_1 = torch.nn.Sequential(
            torch.nn.Conv1d(input_channels,32,3,2,1),
            torch.nn.BatchNorm1d(32),
            torch.nn.Hardswish()
        )
        self.stage_2 = torch.nn.Sequential(
            MB_block(32,16,3,1,1)
        )
        self.stage_3 = torch.nn.Sequential(
            MB_block(16,24,3,2,6),
            MB_block(24,24,3,1,6)
        )
        self.stage_4 = torch.nn.Sequential(
            MB_block(24,40,5,2,6),
            MB_block(40,40,5,1,6)
        )
        self.stage_5 = torch.nn.Sequential(
            MB_block(40,80,3,2,6),
            MB_block(80,80,3,1,6),
            MB_block(80,80,3,1,6),
        )
        self.stage_6 = torch.nn.Sequential(
            MB_block(80,112,5,1,6),
            MB_block(112,112,5,1,6),
            MB_block(112,112,5,1,6),
        )
        self.stage_7 = torch.nn.Sequential(
            MB_block(112,192,5,2,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
        )
        self.stage_8 = torch.nn.Sequential(
            MB_block(192,320,3,1,6)
        )
        self.stage_9 = torch.nn.Sequential(
            torch.nn.Conv1d(320,1280,1),
            torch.nn.AdaptiveAvgPool1d(1),
            torch.nn.Flatten(),
            torch.nn.Linear(1280,classes)
        )
    def forward(self,x):
        x = self.stage_1(x)
        x = self.stage_2(x)
        x = self.stage_3(x)
        x = self.stage_4(x)
        x = self.stage_5(x)
        x = self.stage_6(x)
        x = self.stage_7(x)
        x = self.stage_8(x)
        x = self.stage_9(x)
        return x

if __name__ == '__main__':
    x = torch.randn(1,1,224)
    model = EfficientNet(1,10)
    y = model(x)
    print(y.shape)

🌜 二维EfficientNet搭建 🌛

   二维网络的搭建除了把各个一维网络层改为二维之外,还需要主义注意力机制的更改,下面是注意力机制更改的代码:

import torch

class SE_block(torch.nn.Module):
    def __init__(self,inchannel,ratio = 4):
        super().__init__()
        self.pool = torch.nn.AdaptiveAvgPool2d(1)
        self.conv = torch.nn.Sequential(
            torch.nn.Linear(inchannel,inchannel // ratio),
            torch.nn.ReLU(),
            torch.nn.Linear(inchannel // ratio,inchannel),
            torch.nn.Hardsigmoid(inplace=True)
        )

    def forward(self,input):
        b,c,_,_ = input.size()
        x = self.pool(input)
        x = x.view([b,c])
        x = self.conv(x)
        x = x.view([b,c,1,1])
        return x*input

   这里主要就是在前项传播模块中加入处理二维数组的因素。
   下面是完整代码:

import torch

class SE_block(torch.nn.Module):
    def __init__(self,inchannel,ratio = 4):
        super().__init__()
        self.pool = torch.nn.AdaptiveAvgPool2d(1)
        self.conv = torch.nn.Sequential(
            torch.nn.Linear(inchannel,inchannel // ratio),
            torch.nn.ReLU(),
            torch.nn.Linear(inchannel // ratio,inchannel),
            torch.nn.Hardsigmoid(inplace=True)
        )

    def forward(self,input):
        b,c,_,_ = input.size()
        x = self.pool(input)
        x = x.view([b,c])
        x = self.conv(x)
        x = x.view([b,c,1,1])
        return x*input

class MB_block(torch.nn.Module):
    def __init__(self,input_channels,outchannel,kernal,stride,expand_ratio):
        super().__init__()
        self.input_channels = input_channels
        self.outchannel = outchannel
        self.stride = stride
        self.conv = torch.nn.Sequential(
            torch.nn.Conv2d(input_channels,input_channels*expand_ratio,1),
            torch.nn.BatchNorm2d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            torch.nn.Conv2d(input_channels*expand_ratio,input_channels*expand_ratio,kernal,stride,padding=kernal // 2,groups=input_channels*expand_ratio),
            torch.nn.BatchNorm2d(input_channels*expand_ratio),
            torch.nn.Hardswish(),
            SE_block(input_channels*expand_ratio),
            torch.nn.Conv2d(input_channels*expand_ratio,outchannel,1,1),
            torch.nn.BatchNorm2d(outchannel)
        )
    def forward(self,x):
        out = self.conv(x)
        if self.stride == 1 and self.input_channels == self.outchannel:
            out += x
        return out

class EfficientNet(torch.nn.Module):
    def __init__(self,input_channels,classes):
        super().__init__()
        self.input_channels = input_channels
        self.classes = classes
        self.stage_1 = torch.nn.Sequential(
            torch.nn.Conv2d(input_channels,32,3,2,1),
            torch.nn.BatchNorm2d(32),
            torch.nn.Hardswish()
        )
        self.stage_2 = torch.nn.Sequential(
            MB_block(32,16,3,1,1)
        )
        self.stage_3 = torch.nn.Sequential(
            MB_block(16,24,3,2,6),
            MB_block(24,24,3,1,6)
        )
        self.stage_4 = torch.nn.Sequential(
            MB_block(24,40,5,2,6),
            MB_block(40,40,5,1,6)
        )
        self.stage_5 = torch.nn.Sequential(
            MB_block(40,80,3,2,6),
            MB_block(80,80,3,1,6),
            MB_block(80,80,3,1,6),
        )
        self.stage_6 = torch.nn.Sequential(
            MB_block(80,112,5,1,6),
            MB_block(112,112,5,1,6),
            MB_block(112,112,5,1,6),
        )
        self.stage_7 = torch.nn.Sequential(
            MB_block(112,192,5,2,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
            MB_block(192,192,5,1,6),
        )
        self.stage_8 = torch.nn.Sequential(
            MB_block(192,320,3,1,6)
        )
        self.stage_9 = torch.nn.Sequential(
            torch.nn.Conv2d(320,1280,1),
            torch.nn.AdaptiveAvgPool2d(1),
            torch.nn.Flatten(),
            torch.nn.Linear(1280,classes)
        )
    def forward(self,x):
        x = self.stage_1(x)
        x = self.stage_2(x)
        x = self.stage_3(x)
        x = self.stage_4(x)
        x = self.stage_5(x)
        x = self.stage_6(x)
        x = self.stage_7(x)
        x = self.stage_8(x)
        x = self.stage_9(x)
        return x

if __name__ == '__main__':
    x = torch.randn(1,1,224,224)
    model = EfficientNet(1,10)
    y = model(x)
    print(y.shape)

🌜 总结 🌛

   总体写完感觉这一篇略有点水,但确实这个网络并没有提出很新颖的Block结构或者是Element-wise的操作,所以也没叙述过多。
   模型方面到这里也就结束了, 后续还会有生成数据、数据集打包以及训练等模板, 详情可以看 @浩浩的科研笔记 Pytroch 自写训练模板适合入门版 包含十五种经典的自己复现的一维模型 1D CNN

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
生成对抗网络(GAN)是深度学习领域的一项重要技术,利用GAN可以有效地生成复杂的样本数据,例如图像、音频等。在本文中将介绍如何用pytorch搭建GAN,并对其进行详细的解释。 GAN网络由生成器和判别器两部分组成。生成器接受随机噪声作为输入,通过反向传递训练来生成逼真的样本,而判别器则负责对输入样本进行判断,判断其是否是真实样本。两部分交替训练,并不断优化生成器和判别器的参数,最终可以得到生成器生成逼真样本的能力。 搭建GAN需要先定义生成器和判别器的网络结构,其中生成器可以使用反卷积,而判别器可以使用卷积神经网络。此外,在搭建过程中还需要定义一些超参数,如学习率、训练轮数等。 在开始训练GAN之前,需要先准备好数据集,并对其进行预处理,例如归一化、降噪等。然后对生成器和判别器设置优化器,并开始训练。在训练过程中需要注意调整超参数以达到更好的效果。 最后,在训练结束后需要对GAN进行评估,可以通过计算生成样本与真实样本之间的差别来确定生成器的性能并对其进行改进。 总之,利用pytorch搭建入门GAN需要先定义网络结构和超参数,并使用适当的优化器进行训练,最终可以生成逼真的样本。同时,需要注意调整超参数以达到更好的效果,并对GAN进行评估和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值