首页 > 其他分享 >ShuffleNet V2

ShuffleNet V2

时间:2024-11-22 10:19:56浏览次数:3  
标签:self ShuffleNet channels V2 out size

ShuffleNet V2 是一种轻量级卷积神经网络架构,专为移动设备和资源受限的环境设计。它在 ShuffleNet V1 的基础上进行了优化,尤其在计算效率和实际设备推理速度方面。ShuffleNet V2 由 Megvii (Face++) 团队提出,目标是解决移动设备上的深度学习模型在高效性和准确性之间的平衡问题。


ShuffleNet V2 的核心思想

ShuffleNet V2 的设计核心在于以下几点:

1. 优化实际速度

与 ShuffleNet V1 不同,ShuffleNet V2 不仅关注理论上的 FLOPs(浮点运算次数),还特别关注 实际设备上的速度。它提出了一些影响实际性能的关键原则:

  • 均衡的通道分配:每一层的输入和输出通道数应该保持一致,避免分组卷积的不均匀计算。
  • 减少内存访问成本:减少数据在不同内存之间的频繁传递。
  • 避免过多的分组卷积:虽然分组卷积可以减少计算量,但可能会带来额外的开销。
  • 减少碎片操作:避免复杂的操作,如元素级的操作,保持网络结构简单。
2. 深度可分离卷积

类似于 MobileNet,ShuffleNet V2 也利用了深度可分离卷积,将标准卷积分解为深度卷积和逐点卷积,从而大幅减少计算量和参数量。

3. 通道混洗操作(Channel Shuffle)

通道混洗是 ShuffleNet V 系列的核心创新点。为了在分组卷积中让特征更好地交互,ShuffleNet V2 引入了通道混洗操作:

  • 操作流程
    1. 将输入特征分为多个组。
    2. 对分组的特征图重新排列(打乱顺序)。
  • 优势:通过通道混洗,使得分组卷积的输出特征在后续层可以更好地交互,从而提升表达能力。
4. 分支结构(Branch Structure)

ShuffleNet V2 的倒残差模块采用了分支结构,分为两个并行的路径:

  • 主路径:进行标准卷积、深度卷积和逐点卷积操作。
  • 跳跃路径:直接传递输入,避免额外的计算。

ShuffleNet V2 的结构

ShuffleNet V2 的整体架构是由 多个阶段 堆叠而成,每个阶段由若干个倒残差模块组成。下表列出了 ShuffleNet V2 的主要结构配置:

输出大小通道数模块数量步幅
112×1122412
56×564842
28×289682
14×1419242
7×7102411


ShuffleNet V2 的关键模块

  1. 基本单元(Inverted Residual with Channel Shuffle)

    • 通过通道分组和通道混洗实现高效特征交互。
    • 在轻量级网络中通过分支结构实现快速推理。
  2. 通道混洗(Channel Shuffle)

    • 将通道分组并重新排列。
    • 在多个通道之间提供信息交换,避免分组卷积带来的信息隔离。
  3. 轻量级倒残差块(Lightweight Inverted Residual Block)

    • 在每个分支中使用深度卷积和逐点卷积。
    • 一侧通过深度卷积处理特征,另一侧直接跳跃传递输入,减少计算。

ShuffleNet V2 的优势

  1. 更高效的计算: ShuffleNet V2 不仅关注理论上的计算量(FLOPs),还显著优化了实际设备上的推理速度。

  2. 轻量化设计: 它的模型参数量较小,适合资源受限的移动设备和嵌入式设备。

  3. 优秀的表现: 在 ImageNet 等主流数据集上,ShuffleNet V2 以较少的计算量和参数量取得了与更复杂网络相当的性能。

  4. 模块化与可扩展性: ShuffleNet V2 的设计模块简单,易于在其他模型中集成或扩展。


PyTorch 实现

以下是一个简单的 ShuffleNet V2 加载和推理的代码示例:

import torch
import torch.nn as nn
from torch.autograd import Function


class ChannelShuffleFunction(Function):
    @staticmethod
    def forward(ctx, x, groups):
        batch_size, num_channels, height, width = x.size()
        channels_per_group = num_channels // groups

        # 调整形状并转置
        x = x.view(batch_size, groups, channels_per_group, height, width)
        x = torch.transpose(x, 1, 2).contiguous()

        # 保存张量形状以备后向传播
        ctx.save_for_backward(x)
        ctx.groups = groups

        # 展平
        x = x.view(batch_size, -1, height, width)
        return x

    @staticmethod
    def backward(ctx, grad_output):
        x, = ctx.saved_tensors
        groups = ctx.groups
        batch_size, groups, channels_per_group, height, width = x.size()

        # 调整形状并转置回去
        grad_output = grad_output.view(batch_size, channels_per_group, groups, height, width)
        grad_output = torch.transpose(grad_output, 1, 2).contiguous()
        grad_output = grad_output.view(batch_size, -1, height, width)
        return grad_output, None

class ChannelShuffle(nn.Module):
    def __init__(self, groups):
        super(ChannelShuffle, self).__init__()
        self.groups = groups

    def forward(self, x):
        return ChannelShuffleFunction.apply(x, self.groups)

class Conv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, padding=0, groups=1, stride=1):
        super(Conv, self).__init__()
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride, padding=padding, groups=groups)
        self.bn = nn.BatchNorm2d(num_features=out_channels)
        self.relu = nn.ReLU()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.relu(x)
        return x
class Conv_DW(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, padding, stride=1):
        super(Conv_DW, self).__init__()
        self.conv = nn.Conv2d(in_channels=in_channels, out_channels=out_channels, kernel_size=kernel_size, stride=stride, padding=padding, groups=in_channels)
        self.bn = nn.BatchNorm2d(num_features=out_channels)

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        return x


class ChannelSplit(nn.Module):
    def __init__(self, split_ratio=0.5):
        super(ChannelSplit, self).__init__()
        self.split_ratio = split_ratio

    def forward(self, x):
        # 确定分割点
        c = x.size(1)
        split_point = int(c * self.split_ratio)

        # 分割通道
        x1, x2 = torch.split(x, [split_point, c - split_point], dim=1)
        return x1, x2

class Shuffle1(nn.Module):
    def __init__(self, channels):
        super(Shuffle1, self).__init__()
        self.split = ChannelSplit(split_ratio=0.5)
        channels = channels // 2
        self.conv1 = Conv(in_channels=channels, out_channels=channels, kernel_size=1, padding=0)
        self.conv2 = Conv_DW(in_channels=channels, out_channels=channels, kernel_size=3, padding=1)
        self.conv3 = Conv(in_channels=channels, out_channels=channels, kernel_size=1, padding=0)
        self.shuffle = ChannelShuffle(groups=2)

    def forward(self, x):
        x1, x2 = self.split(x)
        x1 = self.conv1(x1)
        x1 = self.conv2(x1)
        x1 = self.conv3(x1)
        x = torch.cat([x1, x2], dim=1)
        x = self.shuffle(x)
        return x

class Shuffle2(nn.Module):
    def __init__(self, in_channels, out_channels):
        super(Shuffle2, self).__init__()
        out_channels = out_channels // 2
        self.conv1 = Conv(in_channels=in_channels, out_channels=out_channels, kernel_size=1, padding=0)
        self.conv2 = Conv_DW(in_channels=out_channels, out_channels=out_channels, kernel_size=3, stride=2, padding=1)
        self.conv3 = Conv(in_channels=out_channels, out_channels=out_channels, kernel_size=1, padding=0)
        self.conv4 = Conv_DW(in_channels=in_channels, out_channels=in_channels, kernel_size=3, stride=2, padding=1)
        self.conv5 = Conv(in_channels=in_channels, out_channels=out_channels, kernel_size=1, padding=0)
        self.shuffle = ChannelShuffle(groups=2)

    def forward(self, x):
        x1 = self.conv1(x)
        x1= self.conv2(x1)
        x1 = self.conv3(x1)
        x2 = self.conv4(x)
        x2 = self.conv5(x2)
        x = torch.cat([x1, x2], dim=1)
        x = self.shuffle(x)
        return x


class MyNetwork(nn.Module):
    '''一般在init中来构建网络算子层的初始属性'''

    def __init__(self, num_class):
        # 继承父类中的初始构造函数
        super(MyNetwork, self).__init__()
        self.conv = nn.Sequential(
            Conv(in_channels=3, out_channels=24, kernel_size=3, padding=1, stride=2),
            nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
            Shuffle2(in_channels=24, out_channels=116),
            Shuffle1(channels=116),
            Shuffle1(channels=116),
            Shuffle1(channels=116),
            Shuffle2(in_channels=116, out_channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle1(channels=232),
            Shuffle2(in_channels=232, out_channels=464),
            Shuffle1(channels=464),
            Shuffle1(channels=464),
            Shuffle1(channels=464),
            Conv(in_channels=464, out_channels=1024, kernel_size=1, padding=0),
            nn.AdaptiveAvgPool2d((1, 1)),
            Conv(in_channels=1024, out_channels=num_class, kernel_size=1, padding=0)
        )
        self.flat = nn.Flatten()
        self.softmax = nn.Softmax(dim=1)  # 分类层

    ''' forward,必须叫这个名称。但是输入的参数,可以有多少。至少有1个input_X'''

    def forward(self, input_X):
        x = self.conv(input_X)
        x = self.flat(x)
        out = self.softmax(x)
        return out

ShuffleNet V2 的应用场景

  1. 移动设备图像分类: ShuffleNet V2 是专为移动设备设计的,可以快速完成图像分类任务。

  2. 实时目标检测: 结合 SSD、YOLO 等目标检测框架,ShuffleNet V2 能够以较低的计算成本完成实时目标检测任务。

  3. 嵌入式系统: 由于其计算和内存的高效性,ShuffleNet V2 被广泛应用于物联网和嵌入式设备。

  4. 视频流分析: 在实时视频分析任务中,ShuffleNet V2 由于速度快,非常适合部署在摄像头或边缘设备上。


总结

ShuffleNet V2 是一款为移动和嵌入式设备设计的高效轻量级网络,它在优化理论计算量的同时,更注重在实际设备上的速度表现。通过通道混洗和轻量化设计,ShuffleNet V2 提供了一个强大、快速且易于集成的深度学习模型,是现代深度学习轻量化的典范之一。

标签:self,ShuffleNet,channels,V2,out,size
From: https://blog.csdn.net/qq_67654130/article/details/143963000

相关文章

  • gscoolink:gsv2001的sdk移植
    1前言  以gsv的sdk的应用代码为例,将应用代码从m0核移植到m1核的mcu上;  因为用的是hal库,所以互相移植修改的并不多;实际改个头文件就可以编译了;  虽然我hal库用的是m1核的hal库,但是实际上我直接啥也没改,跑在m4核的gdf303上也没啥问题;2修改项目名  修改.uprojx的名字,......
  • 【老白学 Java】Warship v2.0(一)
    Warshipv2.0(一)文章来源:《HeadFirstJava》修炼感悟。上一篇,简版的「Warship」项目终于完工。从本章开始,老白准备在简版基础上进行升级改造,逐步打造出「Warshipv2.0」。开篇前,老白先介绍一下「数组列表」对象,它是这个项目不可缺少的重要工具。如果师兄们感兴趣,可以......
  • 界面控件DevExpress Blazor UI v24.1新版亮点:发布全新文件输入等组件
    DevExpress BlazorUI组件使用了C#为BlazorServer和BlazorWebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生BlazorUI组件(包括PivotGrid、调度程序、图表、数据编辑器和报表等)。DevExpress Blazor控件目前已经升级到v24.1版本了,此版本发布了全新文件输入......
  • Invicti-Professional-v24.11
    0x01工具介绍Invicti(以前称为Netsparker)是一款自动化Web应用程序安全扫描器,旨在帮助组织持续扫描和保护其Web应用程序和API。Invicti注重准确性和效率,使安全团队能够扩展测试工作,同时最大限度地减少误报,确保资源用于解决真正的安全风险。Invicti的突出功能之一是其基......
  • 界面控件DevExpress WinForms v24.2新功能预览 - 支持.NET 9
    DevExpressWinForms 拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!获取DevExpressWinFormsv24.1正式版下载本......
  • 汤臣倍健营销云数据高效集成至金蝶云星辰V2
    汤臣倍健营销云数据集成到金蝶云星辰V2案例分享在企业信息化建设中,数据的高效流转和准确对接是关键。本文将详细介绍如何通过轻易云数据集成平台,将汤臣倍健营销云的数据无缝集成到金蝶云星辰V2系统中,以实现经销商=>客户-(Life-Space)广州闽健的业务需求。为了确保数据集成过程的高......
  • 24-OpenCVSharp —- Cv2.GetPerspectiveTransform()函数功能(透视变换矩阵)详解
    专栏地址:《OpenCV功能使用详解200篇》《OpenCV算子使用详解300篇》《Halcon算子使用详解300篇》内容持续更新,欢迎点击订阅Cv2.GetPerspectiveTransform()是OpenCV中用于计算透视变换矩阵的函数。透视变换(PerspectiveTransform)是计算机视觉和图像处理中常见......
  • 26-OpenCVSharp —- Cv2.WarpPerspective()函数功能(透视变换)详解
    专栏地址:《OpenCV功能使用详解200篇》《OpenCV算子使用详解300篇》《Halcon算子使用详解300篇》内容持续更新,欢迎点击订阅OpenCVSharp—Cv2.WarpPerspective()函数详解Cv2.WarpPerspective()是OpenCV中用于执行透视变换的函数。透视变换(PerspectiveTra......
  • openEuler-22.03安装部署PrometheusV2.16.0
    环境下载安装包GIT下载地址:PrometheusV2.16.0下载使用GitHub文件加速-CSDN博客安装创建prometheus用户及组,并指定家目录[root@manager~]#groupaddprometheus[root@manager~]#useradd-gprometheusprometheus-d/opt/prometheus/将家目录做为prometheus的安装目......
  • 界面控件DevExpress WinForms v24.2新功能预览 - 支持.NET 9
    DevExpressWinForms 拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!获取DevExpressWinFormsv24.1正式版下载DevEx......