ShuffleNetV2 结构(附源码)

【深度学习】(5) ShuffleNetV2 代码复现,网络解析,附pytorch完整代码 在同等复杂度的情况下,ShuffleNetV2 要比 ShuffleNetV1 和 MobileNetV1 更加准确。这个网络的优势在于:(1)作为轻量级的卷积神经网络,ShuffleNetV2 相比其他轻量级模型速度稍快,准确率也更高;(2)轻量级不仅体现在速度上,还大大地减少了模型的参数量,并且通过设定每个单元的通道数便可以灵活地调整模型的复杂度。 阅读详情

本文不细看paper,只看网络结构和源码实现。

看下ShuffleNetV2的结构吧。
在这里插入图片描述
image是3通道进去,经过conv1和maxpool,
然后stage2~4则是主题,里面stride = 2和 stride = 1的shuffleBlock分别重复几次。

shuffleBlock如下,左边是stride = 1的,右边是stride = 2的。
可以看到下面左右两个结构的区别,

  1. branch1的不同,

  2. branch2的第2层:3x3 DWConv,左边的结构中它是stride=1,右边的结构中它是stride=2,
    这就意味着经过左边的block特征图的尺寸会保持不变;经过右边的block, 特征图尺寸会/2,channel会按照设计的增加。

  3. stride=1的结构只能通过branch2变化channel, 而且branch1和branch2只会得到一部分channel的x(有channel split).
    而stride=2的结构中,branch1和branch2都可以得到完整的x,都可以扩充channel。

整体下来,经过stride=1的block后,特征图会保持原尺寸,
而经过stride = 2的block后,特征图的尺寸会/2,channel按照每个stage表格中的变化。

这也就是为什么stride=2只有一层,而stride=1的block可以重复多次。

举个栗子,stage2的in_channel为24, out_channel为116,
每个block是有2个branch的,这个channel要分配一下,比如左边右边各58,经过最后的Concat, 就是116.
stride = 2时channel会增加,特征图尺寸会减半,而stride = 1时channel不变,特征图尺寸不变。

在这里插入图片描述

class ShuffleNetV2(nn.Module):
    def __init__(
        self,
        model_size="1.5x",
        out_stages=(2, 3, 4),
        with_last_conv=False,
        kernal_size=3,
        activation="ReLU",
        pretrain=True,
    ):
        super(ShuffleNetV2, self).__init__()
        # out_stages can only be a subset of (2, 3, 4)
        assert set(out_stages).issubset((2, 3, 4))

        print("model size is ", model_size)  #1.0x

        self.stage_repeats = [4, 8, 4]
        self.model_size = model_size
        self.out_stages = out_stages
        self.with_last_conv = with_last_conv #False
        self.kernal_size = kernal_size
        self.activation = activation #LeakyReLU
        if model_size == "0.5x":
            self._stage_out_channels = [24, 48, 96, 192, 1024]
        elif model_size == "1.0x":
            self._stage_out_channels = [24, 116, 232, 464, 1024] 
        elif model_size == "1.5x":
            self._stage_out_channels = [24, 176, 352, 704, 1024]
        elif model_size == "2.0x":
            self._stage_out_channels = [24, 244, 488, 976, 2048]
        else:
            raise NotImplementedError

        # building first layer
        input_channels = 3
        output_channels = self._stage_out_channels[0]  #24
        #conv3x3,s=2.3->24,p=1,BN,LeakyReLU
        self.conv1 = nn.Sequential(
            nn.Conv2d(input_channels, output_channels, 3, 2, 1, bias=False),
            nn.BatchNorm2d(output_channels),
            act_layers(activation),
        )
        input_channels = output_channels  #24

        self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, padding=1)

        stage_names = ["stage{}".format(i) for i in [2, 3, 4]] #paper中的stage2~4
        #zip是把几个数组的元素打包,以最短的数组为基准
        for name, repeats, output_channels in zip(
            stage_names, self.stage_repeats, self._stage_out_channels[1:]
        ):
        #看paper中的表格,stride=2的repeat一次,stride=1的repeat多少次
            seq = [
                ShuffleV2Block(
                    input_channels, output_channels, 2, activation=activation
                )
            ]
            for i in range(repeats - 1):
                seq.append(
                    ShuffleV2Block(
                        output_channels, output_channels, 1, activation=activation
                    )
                )
            setattr(self, name, nn.Sequential(*seq))
            input_channels = output_channels
        output_channels = self._stage_out_channels[-1]
        if self.with_last_conv:
            conv5 = nn.Sequential(
                nn.Conv2d(input_channels, output_channels, 1, 1, 0, bias=False),
                nn.BatchNorm2d(output_channels),
                act_layers(activation),
            )
            self.stage4.add_module("conv5", conv5)
        self._initialize_weights(pretrain)

    def forward(self, x):
        x = self.conv1(x)
        x = self.maxpool(x)
        output = []
        for i in range(2, 5):
            stage = getattr(self, "stage{}".format(i))
            x = stage(x)
            if i in self.out_stages:
                output.append(x)
        return tuple(output)

ShuffleNetV2 block

class ShuffleV2Block(nn.Module):
    def __init__(self, inp, oup, stride, activation="ReLU"):
        super(ShuffleV2Block, self).__init__()

        if not (1 <= stride <= 3):
            raise ValueError("illegal stride value")
        self.stride = stride

        branch_features = oup // 2  #每个branch分配一半的channel
        assert (self.stride != 1) or (inp == branch_features << 1)

        if self.stride > 1:
            self.branch1 = nn.Sequential(
                self.depthwise_conv(
                    inp, inp, kernel_size=3, stride=self.stride, padding=1
                ),
                nn.BatchNorm2d(inp),
                nn.Conv2d(
                    inp, branch_features, kernel_size=1, stride=1, padding=0, bias=False
                ),
                nn.BatchNorm2d(branch_features),
                act_layers(activation),
            )
        else:
            self.branch1 = nn.Sequential()

        self.branch2 = nn.Sequential(
            nn.Conv2d(
                inp if (self.stride > 1) else branch_features,
                branch_features,
                kernel_size=1,
                stride=1,
                padding=0,
                bias=False,
            ),
            nn.BatchNorm2d(branch_features),
            act_layers(activation),
            self.depthwise_conv(
                branch_features,
                branch_features,
                kernel_size=3,
                stride=self.stride,
                padding=1,
            ),
            nn.BatchNorm2d(branch_features),
            nn.Conv2d(
                branch_features,
                branch_features,
                kernel_size=1,
                stride=1,
                padding=0,
                bias=False,
            ),
            nn.BatchNorm2d(branch_features),
            act_layers(activation),
        )

    @staticmethod
    def depthwise_conv(i, o, kernel_size, stride=1, padding=0, bias=False):
        return nn.Conv2d(i, o, kernel_size, stride, padding, bias=bias, groups=i)

    def forward(self, x):
        if self.stride == 1:
            x1, x2 = x.chunk(2, dim=1) #在dim=1(channel)上分成2块
            out = torch.cat((x1, self.branch2(x2)), dim=1)
        else:
            out = torch.cat((self.branch1(x), self.branch2(x)), dim=1)

        out = channel_shuffle(out, 2)

        return out

channel shuffle在这篇文章里面说过。
channel数转为矩阵,矩阵转置再压平。

在这里插入图片描述

def channel_shuffle(x, groups):
    # type: (torch.Tensor, int) -> torch.Tensor
    batchsize, num_channels, height, width = x.data.size()
    channels_per_group = num_channels // groups

    # reshape
    #channel变为groups x channels_per_group
    x = x.view(batchsize, groups, channels_per_group, height, width)

	#转置为channels_per_group x groups
    x = torch.transpose(x, 1, 2).contiguous()

    # flatten
    x = x.view(batchsize, -1, height, width)

    return x
轻量级网络——ShuffleNetV2 回顾:轻量级网络——ShuffleNetV1 paper链接:ShuffleNet V2: Practical Guidelines for Efficient CNN Architecture Design 关键内容: ShuffleNetV2中提出了一个关键点,之前的轻量级网络都是通过计算网络复杂度的一个间接度量,即FLOPs为指导。通过计算浮点运算量来描述轻量级网络的快慢。但是从来不直接考虑运行的速度。在移动设备中的运行速度不仅仅需要考虑FLOPs,还需要考虑其他的因素,比如内存访问成本(memory 阅读详情

相关推荐

【魔改YOLOv5-6.x(上)】结合轻量化网络Shufflenetv2、Mobilenetv3和Ghostnet

文章目录前言一、Shufflenetv2论文简介模型概述加入YOLOv5二、Mobilenetv3论文简介模型概述深度可分离卷积逆残差结构SE通道注意力h-swish激活函数加入YOLOv5三、Ghostnet论文简介模型概述加入YOLOv5References 前言 本文使用的YOLOv5版本为v6.1,对YOLOv5-6.x网络结构还不熟悉的同学们,可以移步至:【YOLOv5-6.x】网络模型&源码解析 另外,本文所使用的实验环境为1个GTX 1080 GPU,数据集为VOC2007,超参数为h

weixin_43799388的博客 6万+

深度学习之图像分类(十四)--ShuffleNetV2 网络结构

深度学习之图像分类(十四)ShuffleNetV2 网络结构 目录深度学习之图像分类(十四)ShuffleNetV2 网络结构1. 前言2. Several Practical Guidelines for Efficient Network Architecture Design2.1 Equal channel width minimizes memory access cost (MAC).2.2 Excessive group convolution increases MAC.2.3 Networ

木卯_THU的博客 1万+

【项目二、蜂巢检测项目】二、模型改进:YOLOv5s-ShuffleNetV2

目录前言一、数据集 前言 马上要找工作了,想总结下自己做过的几个小项目。 之前以及总结过了我做的第一个项目:xxx病虫害检测项目,github源码地址:HuKai97/FFSSD-ResNet。优快云讲解地址: 【项目一、xxx病虫害检测项目】1、SSD原理和源码分析 【项目一、xxx病虫害检测项目】2、网络结构尝试改进:Resnet50、SE、CBAM、Feature Fusion 【项目一、xxx病虫害检测项目】3、损失函数尝试:Focal loss 而这篇主要介绍我做的第二个项目,也是实验室项目

qq_38253797的博客 1万+

shufflenet v1/v2的网络结构和实现代码总结(torch)

# 根据torch官方代码修改的shufflenetv2的网络模型 https://github.com/pytorch/vision/blob/main/torchvision/models/shufflenetv2.py # 权重文件下载 download url: https://download.pytorch.org/models/shufflenetv2_x0.5-f707e7126e.pth # 权重文件下载 download url: https://download.pytorch....

BIT_Legend的博客 1万+

主干网络篇 | YOLOv8更换主干网络之ShuffleNetV2

ShuffleNetV2是一种轻量级的神经网络架构,用于图像分类和目标检测任务。它是ShuffleNet的改进版本,旨在提高模型的性能和效率。ShuffleNetV2相比于之前的版本,在保持模型轻量化的同时,提高了模型的准确性和性能。它在计算资源有限的设备上具有较好的应用潜力!~🌈

小哥谈 3212

YOLOv8 利用ShuffleNetV2改进网络结构

将ShuffleNetV2引入YOLOv8的主干网络可以进一步提升模型性能,尤其是在目标检测速度和精度方面。ShuffleNetV2是一种改进的ShuffleNetV1架构,它通过引入Channel Shuffle操作和新的Fire Module结构,在降低模型计算量和参数量的同时,提升了模型的特征提取能力。利用ShuffleNetV2改进YOLOv8的Backbone是一种有效的轻量化方案,可以显著提高模型的推理速度和精度,使其成为移动端和嵌入式设备部署目标检测应用的优选方案。

走向CTO的路上... 1253

将Tensorflow目标检测object_detect API源码中的ssd_mobilenet_v1主结构修改为shufflenetv2

为将模型部署移动端,往往采用轻量级的网络结构,如Mobilenet和shufflenet。最近看到网上一些资料shufflenetv2在ImageNet上有着不错的表现,并且计算量相较于其他轻量级网络结构大幅度减少。之前做目标检测时,通常使用ssd_mobilenet_v1,于是在想将ssd_mobilenet_v1主结构替换为shufflenetv2,是否能在准确性和推理速率上都...

qq_26535271的博客 1249

shuffleNetv2 测试

代码地址: https://github.com/yangyuke001/FIIQA_pytorch/blob/master/shufflenetv2.py 在tx2上, 这个速度90ms,尺度2是115ms,精度比原来高 input = torch.randn(1, 3, 224, 224).cuda() 这个返回最后一层的特征: import torch import t...

jacke121的专栏 2656

基于改进的ShufflenetV2图像分类源码介绍

基于改进的ShufflenetV2图像分类源码介绍 去发现同类优质开源项目:https://gitcode.com/ 此资源库提供了基于ShufflenetV2模型改进后的图像分类源码,旨在提高图像分类任务的准确度。ShufflenetV2是一种轻量级神经网络模型,我们通过对该模型进行优化和改进,使其在保持轻量化的同时,拥有更高的图像分类精度。 资源特点 改进的ShufflenetV2架构:我们...

gitblog_06751的博客 783

YOLOv8 更换主干网络之 ShuffleNetv2 详解

ShuffleNetv2 是一种轻量级高效的卷积神经网络架构,旨在为图像识别任务提供更高的性能和效率。它通过使用通道洗牌 (Channel Shuffling) 和分组卷积 (Group Convolution) 等技术来实现,在保持精度的同时显著降低了模型的计算量和参数量。

走向CTO的路上... 2192

YOLOv8改进,YOLOv8主干网络替换为ShuffleNetV2

ShuffleNet V2的设计原则:1.减少内存访问成本:通过优化数据传输路径,减少内存访问延迟,提高整体运算速度。2.考虑平台特性:针对不同硬件平台的特性进行优化设计,确保在目标平台上的高效运行。3.结构简洁高效:采用简洁而高效的模块设计,降低计算复杂度,同时保持或提升模型的预测准确性。下图,以四种不同计算复杂度水平下的准确性(在ImageNet验证集上的分类),速度和FLOPs的测量结果。(a, c) 为GPU结果,批量大小为8。(b, d) 为ARM结果,批量大小为1。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 1564

基于改进的ShufflenetV2图像分类源码介绍:提升图像分类准确度的强大工具

基于改进的ShufflenetV2图像分类源码介绍:提升图像分类准确度的强大工具 去发现同类优质开源项目:https://gitcode.com/ 在图像分类领域,ShufflenetV2以其轻量级和高效的特性受到广泛关注。本文将介绍一个开源项目,该项目通过改进ShufflenetV2模型,实现了更高精度的图像分类,适用于各种图像识别任务。 项目介绍 基于改进的ShufflenetV2图像分类源码...

gitblog_06749的博客 812

YOLOv8 利用ShuffleNetV1改进网络结构

将ShuffleNetV1引入YOLOv8的主干网络可以提高模型的性能,尤其是在目标检测速度方面。ShuffleNetV1是一种轻量级的深度卷积神经网络架构,它通过ShuffleNet Unit操作来降低模型的计算量和参数量,同时保持较高的模型精度。利用ShuffleNetV1改进YOLOv8的Backbone是一种有效的轻量化方案,可以显著提高模型的推理速度,同时保持较高的模型精度,使其成为移动端和嵌入式设备部署目标检测应用的优选方案。

走向CTO的路上... 1392

RCNN学习笔记-ShuffleNetV2源码分析

RCNN学习笔记-ShuffleNetV2源码分析

guoguozgw的博客 517

YOLOv10改进系列,YOLOv10改进主干网络为ShuffleNetV2

ShuffleNet V2的设计原则:1.减少内存访问成本:通过优化数据传输路径,减少内存访问延迟,提高整体运算速度。2.考虑平台特性:针对不同硬件平台的特性进行优化设计,确保在目标平台上的高效运行。3.结构简洁高效:采用简洁而高效的模块设计,降低计算复杂度,同时保持或提升模型的预测准确性。下图,以四种不同计算复杂度水平下的准确性(在ImageNet验证集上的分类),速度和FLOPs的测量结果。(a, c) 为GPU结果,批量大小为8。(b, d) 为ARM结果,批量大小为1。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 687

在边缘部署实时视觉应用程序

克隆代码库后,压缩源文件夹的内容,并将生成的存档文件上传到上一节中创建的 S3 存储桶中。在本教程中,我们将使用 AWS Greengrass,因为它支持大多数 Windows 和 Linux 设备,包括我们的目标 Jetson AGX Xavier。此外,模型还可以量化到更低的精度,从而加快推理速度,但对于较大的模型,此过程通常较长(约 45 分钟)。本例中的脚本只是启动一个 Bash 环境,切换到解压后的构件目录,最后使用所需的命令行参数运行 Deepstream 应用。每个模型类型都有其独有的格式。

2501_91623519的博客 1281

基于Pytorch框架的深度学习ShufflenetV2神经网络十七种猴子动物识别分类系统源码

基于Pytorch框架的深度学习ShufflenetV2神经网络十七种猴子动物识别分类系统源码

修行之路 2077

PCB布线避坑指南:为什么你的差分线等长总调不好?AD19蛇形等长技巧详解

本文详细解析了AD19环境下PCB差分线等长调整的核心技巧与常见问题。从差分信号等长的底层逻辑到AD19规则配置,再到蛇形等长高级技巧和信号完整性验证,帮助工程师解决差分线等长调整中的难题,提升高速PCB设计的信号质量。

weixin_28738397的博客 382

ShuffleNetV2模型在行空板上的边缘AI部署实战

边缘计算通过在数据源头就近处理信息,有效解决了云端AI在延迟、带宽和隐私方面的瓶颈。其核心原理是将轻量化的神经网络模型部署到资源受限的终端设备上,实现本地实时推理。这一技术价值在于为物联网、智能安防和工业质检等场景提供了低功耗、高响应的智能化解决方案。模型量化作为关键优化手段,能将FP32模型转换为INT8格式,显著减少模型体积并提升推理速度。ONNX作为开放的模型交换格式,打通了从训练框架到多种推理引擎的部署链路。本文以ShuffleNetV2这一经典的轻量化网络和行空板硬件平台为例,详细阐述了从模型训练

weixin_34198453的博客 388

西门子机床数据采集实战:从828D到840DSL的CNC设备联网与实时监控

本文深入探讨了西门子机床数据采集的实战方案,重点解析了从828D到840DSL等CNC设备如何实现免授权、低成本联网与实时监控。文章通过对比不同型号系统的数据接口差异,提供了详细的配置步骤、核心数据点清单以及避坑指南,旨在帮助工厂技术人员经济高效地挖掘机床数据价值,提升生产管理效率。

weixin_29181861的博客 1324

高速电路的信号完整性分析

摘要:介绍了高速PCB设计中的信号完整性概念以及破坏信号完整性的原因,从理论和计算的层面上分析了高速电路设计中反射和串扰的形成原因,并介绍了IBIS仿真。 关键词:信号完整性 反射 串扰 IBIS仿真 随着半导体技术和深压微米工艺的不断发展,IC的开关速度目前已经从几十MHz增加到几百MHz,甚至达到几GHz。在高速PCB设计中,工程师经常会碰到误触发、阻尼振荡、过冲、欠冲、串...

bh_wang的专栏 1430

ShufferNetV1 V2 网络+pytorch源码

ShufferNet v1 channel shuffer的思想 ShufferNet Unit 中全是GConv和DWconv

744

CANape快速上手

文章帮助记录CANape学习过程。

小弱鸡的博客 1万+
上一篇: yolact train过程源码解读(COCO数据集)
下一篇: leetcode 931. Minimum Falling Path Sum(最小的下降路径和)
蓝羽飞鸟
博客等级 码龄8年 1万+粉丝 727原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值