这里有一个交互式版本

https://github.com/FrancescoSaverioZuppichini/BottleNeck-InvertedResidual-FusedMBConv-in-PyTorch/blob/main/README.ipynb

所有这些模块都已在库中实现

今天,我们将看到现代CNN架构中使用的不同模块,如ResNet、MobileNet、EfficientNet,以及它们在PyTorch中的实现。

让我们创建一个通用的conv-norm-act层

from functools import partial
from torch import nnclass ConvNormAct(nn.Sequential):def __init__(self,in_features: int,out_features: int,kernel_size: int,norm: nn.Module = nn.BatchNorm2d,act: nn.Module = nn.ReLU,**kwargs):super().__init__(nn.Conv2d(in_features,out_features,kernel_size=kernel_size,padding=kernel_size // 2,),norm(out_features),act(),)Conv1X1BnReLU = partial(ConvNormAct, kernel_size=1)
Conv3X3BnReLU = partial(ConvNormAct, kernel_size=3)
import torchx = torch.randn((1, 32, 56, 56))Conv1X1BnReLU(32, 64)(x).shape
torch.Size([1, 64, 56, 56])

残差连接

残差连接用于ResNet中,想法是将输入添加到输出中,输出=层+输入。

下图可能会帮助你将其可视化。但是,我的意思是它只是一个+运算符。残差操作提高了梯度传播的能力,允许有效地训练具有100层以上的网络。

在PyTorch中,我们可以轻松创建一个ResidualAdd层

from torch import nn
from torch import Tensorclass ResidualAdd(nn.Module):def __init__(self, block: nn.Module):super().__init__()self.block = blockdef forward(self, x: Tensor) -> Tensor:res = xx = self.block(x)x += resreturn xResidualAdd(nn.Conv2d(32, 32, kernel_size=1)
)(x).shape

shortcut

有时你的残差没有相同的输出维度,所以我们不能添加它们。

我们可以使用shortcut中的卷积投射输入,以匹配输出特征:

from typing import Optionalclass ResidualAdd(nn.Module):def __init__(self, block: nn.Module, shortcut: Optional[nn.Module] = None):super().__init__()self.block = blockself.shortcut = shortcutdef forward(self, x: Tensor) -> Tensor:res = xx = self.block(x)if self.shortcut:res = self.shortcut(res)x += resreturn xResidualAdd(nn.Conv2d(32, 64, kernel_size=1),shortcut=nn.Conv2d(32, 64, kernel_size=1)
)(x).shape

BottleNeck Blocks

在图像识别的深度残差学习中引入了Bottlenecks。Bottlenecks块接受大小为BxCxHxW的输入,它首先使用1x1 卷积将其变为BxC/rxHxW,然后应用3x3 卷积,最后将输出重新映射到与输入相同的特征维度BxCxHxW,然后再次使用1x1卷积。这比使用三个3x3卷积更快。

因为首先减少了输入,所以我们称之为“Bottlenecks”。下图显示了该块,我们在原始实现中使用了r=4

前两个卷积之后是batchnorm和一个非线性激活层,而最后一个非线性层在加法后应用。

在PyTorch中为:

from torch import nnclass BottleNeck(nn.Sequential):def __init__(self, in_features: int, out_features: int, reduction: int = 4):reduced_features = out_features // reductionsuper().__init__(nn.Sequential(ResidualAdd(nn.Sequential(# wide -> narrowConv1X1BnReLU(in_features, reduced_features),# narrow -> narrowConv3X3BnReLU(reduced_features, reduced_features),# narrow -> wideConv1X1BnReLU(reduced_features, out_features, act=nn.Identity),),shortcut=Conv1X1BnReLU(in_features, out_features)if in_features != out_featureselse None,),nn.ReLU(),))BottleNeck(32, 64)(x).shape

请注意,仅当输入和输出特征不同时,我们才应用shortcut。

在实践中,当我们希望减小空间维数时,在卷积中使用stride=2。

Linear BottleNecks

MobileNet V2中引入了Linear Bottleneck。Linear BottleNecks是没有激活函数的Bottlenecks块。

https://arxiv.org/abs/1801.04381

在论文的第3.2节中,他们详细讨论了为什么在输出之前存在非线性会损害性能。简而言之,非线性函数ReLU在<0时设为0会导致破坏信息。因此,在Bottlenecks中删除nn.ReLU你就可以拥有Linear BottleNecks。

倒残差

MobileNet V2中再次引入了倒残差。

https://arxiv.org/abs/1801.04381

倒残差块是反向的Bottlenecks层。它们通过第一次卷积扩展特征,而不是减少特征。

下图应该可以清楚地说明这一点

我们从BxCxHxW到->BxCxHxW->BxCxHxW->BxCxHxW,其中e是膨胀率,它被设置为4。而不是像在正常的Bottlenecks区那样变宽->变窄->变宽,而是相反,变窄->变宽->变窄。

在PyTorch中,实现如下

class InvertedResidual(nn.Sequential):def __init__(self, in_features: int, out_features: int, expansion: int = 4):expanded_features = in_features * expansionsuper().__init__(nn.Sequential(ResidualAdd(nn.Sequential(# narrow -> wideConv1X1BnReLU(in_features, expanded_features),# wide -> wideConv3X3BnReLU(expanded_features, expanded_features),# wide -> narrowConv1X1BnReLU(expanded_features, out_features, act=nn.Identity),),shortcut=Conv1X1BnReLU(in_features, out_features)if in_features != out_featureselse None,),nn.ReLU(),))InvertedResidual(32, 64)(x).shape

在MobileNet中,只有当输入和输出特征匹配时,才会应用残差连接

class MobileNetLikeBlock(nn.Sequential):def __init__(self, in_features: int, out_features: int, expansion: int = 4):# use ResidualAdd if features match, otherwise a normal Sequentialresidual = ResidualAdd if in_features == out_features else nn.Sequentialexpanded_features = in_features * expansionsuper().__init__(nn.Sequential(residual(nn.Sequential(# narrow -> wideConv1X1BnReLU(in_features, expanded_features),# wide -> wideConv3X3BnReLU(expanded_features, expanded_features),# wide -> narrowConv1X1BnReLU(expanded_features, out_features, act=nn.Identity),),),nn.ReLU(),))MobileNetLikeBlock(32, 64)(x).shape
MobileNetLikeBlock(32, 32)(x).shape

MBConv

MobileNet V2的构建块被称为MBConv。MBConv是具有深度可分离卷积的倒残差的Linear BottleNecks层。

深度可分离卷积

深度可分离卷积采用一种技巧,将一个正常的3x3卷积夹在两个卷积中,以减少参数数量。

第一个对每个输入的通道应用单个3x3滤波器,另一个对所有通道应用1x1滤波器。

这与正常的3x3卷积相同,但你节省了参数。

然而它比我们现有硬件上的普通3x3慢得多。

下图显示了这个想法

通道中的不同颜色表示每个通道应用的单个过滤器

PyTorch中:

class DepthWiseSeparableConv(nn.Sequential):def __init__(self, in_features: int, out_features: int):super().__init__(nn.Conv2d(in_features, in_features, kernel_size=3, groups=in_features),nn.Conv2d(in_features, out_features, kernel_size=1))DepthWiseSeparableConv(32, 64)(x).shape

第一次卷积通常称为depth,而第二次卷积称为point。让我们统计参数量

sum(p.numel() for p in DepthWiseSeparableConv(32, 64).parameters() if p.requires_grad)

输出:2432

让我们看一个普通的Conv2d

sum(p.numel() for p in nn.Conv2d(32, 64, kernel_size=3).parameters() if p.requires_grad)

输出:18496

有很大的区别

实现MBConv

那么,让我们创建一个完整的MBConv。

MBConv有几个重要的细节,标准化应用于深度和点卷积,非线性仅应用于深度卷积(Linear Bottlenecks)。

class MBConv(nn.Sequential):def __init__(self, in_features: int, out_features: int, expansion: int = 4):residual = ResidualAdd if in_features == out_features else nn.Sequentialexpanded_features = in_features * expansionsuper().__init__(nn.Sequential(residual(nn.Sequential(# narrow -> wideConv1X1BnReLU(in_features, expanded_features,act=nn.ReLU6),# wide -> wideConv3X3BnReLU(expanded_features, expanded_features, groups=expanded_features,act=nn.ReLU6),# here you can apply SE# wide -> narrowConv1X1BnReLU(expanded_features, out_features, act=nn.Identity),),),nn.ReLU(),))MBConv(32, 64)(x).shape

Fused MBConv

EfficientNetV2中引入了融合倒残差:

https://arxiv.org/abs/2104.00298

所以基本上,由于深度卷积比较慢,他们将第一个和第二个卷积融合在一个3x3的卷积中(第3.2节)。

class FusedMBConv(nn.Sequential):def __init__(self, in_features: int, out_features: int, expansion: int = 4):residual = ResidualAdd if in_features == out_features else nn.Sequentialexpanded_features = in_features * expansionsuper().__init__(nn.Sequential(residual(nn.Sequential(Conv3X3BnReLU(in_features, expanded_features, act=nn.ReLU6),# here you can apply SE# wide -> narrowConv1X1BnReLU(expanded_features, out_features, act=nn.Identity),),),nn.ReLU(),))MBConv(32, 64)(x).shape

结论

现在你应该知道所有这些块之间的区别以及它们背后的原因了!强烈建议你阅读与他们相关的论文

有关ResNet的更详细检测,请查看:

https://towardsdatascience.com/residual-network-implementing-resnet-a7da63c7b278

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

Residual, BottleNeck, Linear BottleNeck, MBConv解释相关推荐

  1. MobileNet v2中 Inverted Residual 和 Linear Bottleneck 是怎么回事

    MobileNet v2中 Inverted Residual 和 Linear Bottleneck 是怎么回事 flyfish MobileNet v1的深度可分离卷积 Block的结构 先从Mo ...

  2. residual block、bottleneck、skip connection……都是些什么?

      最近在看论文的时候,总是时不时会看到residual block.bottleneck.skip connection等术语,于是花了点时间找了几篇高质量的问答贴看了一下(链接附在本文末尾),并将 ...

  3. 深度学习之bottleneck layer

    一. bottleneck layery中文名称:瓶颈层.我初次接触也就是在残差网络中.一般在较深的网络中,如resnet101中使用. 一般的结构如下: 其中两个1X1fliter分别用于降低和升高 ...

  4. 【MobileNet V2】《MobileNetV2:Inverted Residuals and Linear Bottlenecks》

    CVPR-2018 caffe 版本的代码:https://github.com/shicai/MobileNet-Caffe/blob/master/mobilenet_v2_deploy.prot ...

  5. 轻量型网络之MobileNetV2: Inverted Residuals and Linear Bottlenecks论文学习

    0.摘要 针对残差结构提出来倒残差结构(Inverted Residuals),由于使用的是1x1卷积在resnet中也叫瓶颈层,所以这个模块最终叫做具有线性瓶颈的倒残差结构(the inverted ...

  6. 轻量化网络(二)MobileNetV2: Inverted Residuals and Linear Bottlenecks

    论文链接 Pytorch实现 Tensorflow实现 Mobilenet V2是谷歌在Mobilenet V1上的进一步改进,第一版参考文章,是Mobilenet系列的第二篇.该文章以深度可分离卷积 ...

  7. 论文精读:MobileNetV2: Inverted Residuals and Linear Bottlenecks

    论文地址:https://arxiv.org/pdf/1801.04381.pdf 模型结构简单,重点是理解模型设计的动机,并记录一下卷积的通用知识,已经熟知的知识就不再记录了,详细读原文. Abst ...

  8. 简记MobileNet系列

    <简记MobileNet系列>   ImageNet竞赛至今,为了追求精度,模型深度越来越深,参数量也越来越大,这导致移动端场景的算力是无法支撑的.所以轻量级模型应运而生,Google提出 ...

  9. 轻量级网络——MobileNet系列学习(理论篇)

    目录 一.MobileNetV1 1.1 Depthwise separable convolution(深度级可分离卷积) 参数对比 1.2 MobileNet网络结构 1.3 MobileNet网 ...

最新文章

  1. 集成服务入门(实验10)使用事务和检查点
  2. python安装whl_EN-mysqlclient库安装问题
  3. 大数据WEB阶段(九)Myeclipse中配置Tomcat并发布项目
  4. 马斯克挽尊,回应为何电动皮卡车窗玻璃怼不过钢球...
  5. 二分查找法(Java实现)
  6. MyBatis映射文件3(参数处理Map)
  7. java乐视面试题_乐视面试题 · vagabond1-1983/JavaRock Wiki · GitHub
  8. Android Builder模式
  9. Linux C聊天室的实现
  10. 现在PayPal还可以怎样提现???账户只有91刀!
  11. i春秋 - Exploit-Exercises: Nebula - level06
  12. 漫谈bufferbloat以及TCP公平性
  13. GRUB legacy和GRUB 2介绍 与 命令【包含kernel 与 initrd的详解】使用
  14. STM32定时 计算公式
  15. 如何查看Linux系统的版本
  16. Stereogram(极射赤面)投影--主要用于中高纬和极区的天气图
  17. Headless CMS Sanity 数据建模——定义文档内容的结构
  18. 百度网盘下载慢怎么解决
  19. creo怎么画线_cero草绘基础图文教程,教你CREO工程图绘制中心线的方法
  20. 分页存储的地址空间是一维的,分段存储的地址空间是二维的

热门文章

  1. Response对象及常用方法
  2. 2022摩根士丹利笔试
  3. Deep Learning 1:简单线性分类
  4. 申请外观专利如何简要描述外观?
  5. shallowRef和shallowReactive
  6. 华为云发布CodeArts Req需求管理工具,让需求管理化繁为简
  7. PD-QC-AFC多协议诱骗芯片《LDR6328S》
  8. 由想象到现实,机器人花了半个世纪的时间
  9. python对变量和值的管理方式_变量 常量 Python变量内存管理 赋值方式 注释
  10. 图的应用1---单源最短路径问题