Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >YOLOv8轻量化:RepGhost,通过重参数化实现硬件高效的Ghost模块

YOLOv8轻量化:RepGhost,通过重参数化实现硬件高效的Ghost模块

原创
作者头像
AI小怪兽
发布于 2023-11-09 01:03:25
发布于 2023-11-09 01:03:25
2.5K00
代码可运行
举报
文章被收录于专栏:YOLO大作战YOLO大作战
运行总次数:0
代码可运行

💡💡💡本文独家改进:RepGhost,通过重参数化实现硬件高效的Ghost模块,性能优于GhostNet、MobileNetV3等,在移动设备上具有更少的参数和可比的延迟。

RepGhost和C2f结合 | 轻量化的同时在数据集并有小幅涨点;

性能比较

layers

parameters

GFLOPs

kb

YOLOv8s

168

11125971

28.4

21991

yolov8_C2f_repghosts

352

2589699

7

5341

1.RepGhost介绍

论文:https://arxiv.org/pdf/2211.06088.pdf

特征重用一直是轻量级卷积神经网络(CNN)设计中的关键技术。当前的方法通常利用级联运算符通过重用来自其他层的特征图来廉价地保持大通道数(从而大网络容量)。尽管级联是无参数和无FLOPs的,但其在硬件设备上的计算成本是不可忽略的。

为了解决这个问题,本文提供了一个通过结构重参数化技术实现特征重用的新视角。提出了一种新的硬件高效的RepGhost模块,用于通过重参数化实现隐式特征重用,而不是使用级联运算符。

图3.从Ghost模块到RepGhost模块的演变。我们省略了输入的1x1卷积,更多的结构细节请参见图4。dconv:深度卷积层(后跟BN)。Cat:连接层。a)带有ReLU的Ghost模块[14];b)用添add替换concat;c)向后移动ReLU,使模块满足结构重新参数化的规则;d)训练过程中的RepGhost模块;e)推理过程中的RepGhost模块。模块c和模块d可以在推理过程中融合到模块e中。

图4:与Ghost bottleneck[14]相比。S Block:跳跃连接块,DS:下采样层,SE:SE块[21]。RG-block :RepGhost bottleneck。虚线中的方块只在必要时插入。Cin、Cmid和Cout分别表示bottleneck的输入通道、中间通道和输出通道。请注意,这些被标记为红色的bottleneck,即RepGhost bottleneck不同于bottleneck内部通道中的Ghost bottleneck。

2.Yolov8引入RepGhost

2.1 加入ultralytics/nn/backbone/repghost.py

​核心代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class RepGhostModule(nn.Module):
    def __init__(
            self, inp, oup, kernel_size=1, dw_size=3, stride=1, relu=True, deploy=False, reparam_bn=True,
            reparam_identity=False
    ):
        super(RepGhostModule, self).__init__()
        init_channels = oup
        new_channels = oup
        self.deploy = deploy

        self.primary_conv = nn.Sequential(
            nn.Conv2d(
                inp, init_channels, kernel_size, stride, kernel_size // 2, bias=False,
            ),
            nn.BatchNorm2d(init_channels),
            nn.SiLU(inplace=True) if relu else nn.Sequential(),
        )
        fusion_conv = []
        fusion_bn = []
        if not deploy and reparam_bn:
            fusion_conv.append(nn.Identity())
            fusion_bn.append(nn.BatchNorm2d(init_channels))
        if not deploy and reparam_identity:
            fusion_conv.append(nn.Identity())
            fusion_bn.append(nn.Identity())

        self.fusion_conv = nn.Sequential(*fusion_conv)
        self.fusion_bn = nn.Sequential(*fusion_bn)

        self.cheap_operation = nn.Sequential(
            nn.Conv2d(
                init_channels,
                new_channels,
                dw_size,
                1,
                dw_size // 2,
                groups=init_channels,
                bias=deploy,
            ),
            nn.BatchNorm2d(new_channels) if not deploy else nn.Sequential(),
            # nn.ReLU(inplace=True) if relu else nn.Sequential(),
        )
        if deploy:
            self.cheap_operation = self.cheap_operation[0]
        if relu:
            self.relu = nn.SiLU(inplace=False)
        else:
            self.relu = nn.Sequential()

    def forward(self, x):
        x1 = self.primary_conv(x)  # mg
        x2 = self.cheap_operation(x1)
        for conv, bn in zip(self.fusion_conv, self.fusion_bn):
            x2 = x2 + bn(conv(x1))
        return self.relu(x2)

    def get_equivalent_kernel_bias(self):
        kernel3x3, bias3x3 = self._fuse_bn_tensor(self.cheap_operation[0], self.cheap_operation[1])
        for conv, bn in zip(self.fusion_conv, self.fusion_bn):
            kernel, bias = self._fuse_bn_tensor(conv, bn, kernel3x3.shape[0], kernel3x3.device)
            kernel3x3 += self._pad_1x1_to_3x3_tensor(kernel)
            bias3x3 += bias
        return kernel3x3, bias3x3

    @staticmethod
    def _pad_1x1_to_3x3_tensor(kernel1x1):
        if kernel1x1 is None:
            return 0
        else:
            return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1])

    @staticmethod
    def _fuse_bn_tensor(conv, bn, in_channels=None, device=None):
        in_channels = in_channels if in_channels else bn.running_mean.shape[0]
        device = device if device else bn.weight.device
        if isinstance(conv, nn.Conv2d):
            kernel = conv.weight
            assert conv.bias is None
        else:
            assert isinstance(conv, nn.Identity)
            kernel_value = np.zeros((in_channels, 1, 1, 1), dtype=np.float32)
            for i in range(in_channels):
                kernel_value[i, 0, 0, 0] = 1
            kernel = torch.from_numpy(kernel_value).to(device)

        if isinstance(bn, nn.BatchNorm2d):
            running_mean = bn.running_mean
            running_var = bn.running_var
            gamma = bn.weight
            beta = bn.bias
            eps = bn.eps
            std = (running_var + eps).sqrt()
            t = (gamma / std).reshape(-1, 1, 1, 1)
            return kernel * t, beta - running_mean * gamma / std
        assert isinstance(bn, nn.Identity)
        return kernel, torch.zeros(in_channels).to(kernel.device)

    def switch_to_deploy(self):
        if len(self.fusion_conv) == 0 and len(self.fusion_bn) == 0:
            return
        kernel, bias = self.get_equivalent_kernel_bias()
        self.cheap_operation = nn.Conv2d(in_channels=self.cheap_operation[0].in_channels,
                                         out_channels=self.cheap_operation[0].out_channels,
                                         kernel_size=self.cheap_operation[0].kernel_size,
                                         padding=self.cheap_operation[0].padding,
                                         dilation=self.cheap_operation[0].dilation,
                                         groups=self.cheap_operation[0].groups,
                                         bias=True)
        self.cheap_operation.weight.data = kernel
        self.cheap_operation.bias.data = bias
        self.__delattr__('fusion_conv')
        self.__delattr__('fusion_bn')
        self.fusion_conv = []
        self.fusion_bn = []
        self.deploy = True


class RepGhostBottleneck(nn.Module):
    """RepGhost bottleneck w/ optional SE"""

    def __init__(
            self,
            in_chs,
            mid_chs,
            out_chs,
            dw_kernel_size=3,
            stride=1,
            se_ratio=0.0,
            shortcut=True,
            reparam=True,
            reparam_bn=True,
            reparam_identity=False,
            deploy=False,
    ):
        super(RepGhostBottleneck, self).__init__()
        has_se = se_ratio is not None and se_ratio > 0.0
        self.stride = stride
        self.enable_shortcut = shortcut
        self.in_chs = in_chs
        self.out_chs = out_chs

        # Point-wise expansion
        self.ghost1 = RepGhostModule(
            in_chs,
            mid_chs,
            relu=True,
            reparam_bn=reparam and reparam_bn,
            reparam_identity=reparam and reparam_identity,
            deploy=deploy,
        )

        # Depth-wise convolution
        if self.stride > 1:
            self.conv_dw = nn.Conv2d(
                mid_chs,
                mid_chs,
                dw_kernel_size,
                stride=stride,
                padding=(dw_kernel_size - 1) // 2,
                groups=mid_chs,
                bias=False,
            )
            self.bn_dw = nn.BatchNorm2d(mid_chs)

        # Squeeze-and-excitation
        if has_se:
            self.se = SqueezeExcite(mid_chs, se_ratio=se_ratio)
        else:
            self.se = None

        # Point-wise linear projection
        self.ghost2 = RepGhostModule(
            mid_chs,
            out_chs,
            relu=False,
            reparam_bn=reparam and reparam_bn,
            reparam_identity=reparam and reparam_identity,
            deploy=deploy,
        )

        # shortcut
        if in_chs == out_chs and self.stride == 1:
            self.shortcut = nn.Sequential()
        else:
            self.shortcut = nn.Sequential(
                nn.Conv2d(
                    in_chs,
                    in_chs,
                    dw_kernel_size,
                    stride=stride,
                    padding=(dw_kernel_size - 1) // 2,
                    groups=in_chs,
                    bias=False,
                ),
                nn.BatchNorm2d(in_chs),
                nn.Conv2d(
                    in_chs, out_chs, 1, stride=1,
                    padding=0, bias=False,
                ),
                nn.BatchNorm2d(out_chs),
            )

    def forward(self, x):
        residual = x
        x1 = self.ghost1(x)
        if self.stride > 1:
            x = self.conv_dw(x1)
            x = self.bn_dw(x)
        else:
            x = x1

        if self.se is not None:
            x = self.se(x)

        # 2nd repghost bottleneck mg
        x = self.ghost2(x)
        if not self.enable_shortcut and self.in_chs == self.out_chs and self.stride == 1:
            return x
        return x + self.shortcut(residual)

详见:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://blog.csdn.net/m0_63774211/article/details/132022000

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
工程必备!轻量级网络面试题!!
所示,左边为常见的普通卷积运算,输出的每一个维度的特征都需要输入特征的每一个维度经过计算获得,但这样的计算量会比较大。因而在
灿视学长
2021/07/07
4170
Yolov8轻量化改进:Ghostnet、G_ghost、Ghostnetv2家族大作战(二):华为Ghostnetv2,端侧小模型性能新SOTA
引入到yolov8,Bottleneck与c2f结合,代替backbone中的所有c2f。
AI小怪兽
2023/10/31
5.2K0
【AI系统】GhostNet 系列
本文主要会介绍 GhostNet 系列网络,在本文中会给大家带来卷积结构的改进方面的轻量化,以及与注意力(self-attention)模块的进行结合,部署更高效,更适合移动计算的 GhostNetV2。让读者更清楚的区别 V2 与 V1 之间的区别。
用户11307734
2024/12/05
1200
YOLOv8轻量级:Ghostnet、G_ghost、Ghostnetv2家族大作战(三):华为GhostNet再升级,全系列硬件最优极简AI网络G_ghost
引入到yolov8,Bottleneck与c2f结合,代替backbone中的所有c2f。
AI小怪兽
2023/11/01
1.4K0
使用PyTorch复现ConvNext:从Resnet到ConvNext的完整步骤详解
ConvNext论文提出了一种新的基于卷积的架构,不仅超越了基于 Transformer 的模型(如 Swin),而且可以随着数据量的增加而扩展!今天我们使用Pytorch来对其进行复现。下图显示了针对不同数据集/模型大小的 ConvNext 准确度。
deephub
2022/06/04
1.5K0
使用PyTorch复现ConvNext:从Resnet到ConvNext的完整步骤详解
​深度神经网络经典模型结构-shufflenet系列
卷积神经网络在计算机视觉任务中表现优异,但由于嵌入式设备内存空间小,能耗要求低,因此需要使用更加高效的模型。例如,与单纯的堆叠卷积层相比GoogLeNet增加了网络的宽度但降低了复杂度,SqueezeNet在保持精度的同时大大减少参数和计算量,ResNet利用高效的bottleneck结构实现惊人的效果,Xception中提出深度可分卷积概括了Inception序列,MobileNet利用深度可分卷积构建的轻量级模型获得了不错的效果,Senet(取得了 ImageNet 2017 的冠军)引入了一个架构单元对 Channel 之间的信息进行显式建模,它以很小的计算成本提高了性能。而ShuffleNet主要使用了pointwise group convolution(分组的1×1卷积核)代替密集的1×1卷积来减小计算复杂度(因为作者发现,对于resnext中的每个residual unit,1×1卷积(逐点卷积)占据93.4%的运算)。同时为了消除pointwise group convolution带来的副作用,提出了一个新的channel shuffle操作来使得信息能够在特征通道上进行交叉流动,因此shuffleNet在保持原有准确率的条件下大大降低计算量。
小草AI
2019/11/01
2K0
​深度神经网络经典模型结构-shufflenet系列
Yolov8-pose关键点检测:模型轻量化设计 | 模型压缩率从6842降低到1018,GFLOPs从9.6降低至2.2
轻量化模型设计:模型压缩率从6842降低到1018,GFLOPs从9.6降低至2.2, mAP50从0.921变为0.92(几乎不变)
AI小怪兽
2023/12/08
1.7K1
CVPR | 超越MobileNetV3的轻量级网络(文末论文下载)
CVPR都会出先需要优质文章,今天我看到一篇之前的paper了,今天给大家分享,它就是超越Mobilenet_V3的轻量级网络——GhostNet。
计算机视觉研究院
2022/01/25
1.1K0
CVPR | 超越MobileNetV3的轻量级网络(文末论文下载)
【AI系统】ShuffleNet 系列
本文会介绍 ShuffleNet 系列,重点在于其模型结构的轻量化设计,涉及如何降低深度网络计算量,在本文中会着重会讲解逐点分组卷积(Pointwise Group Convolution)和通道混洗(Channel Shuffle)两种新的运算,而 V2 版本则会从设备运算速度方面考虑将网络进行轻量化。
用户11307734
2024/12/02
1160
PyTorch建立resnet34和resnet101代码[通俗易懂]
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/11/10
7490
ResNet34+Unet(可以直接用)
四次Skipconnect分别在:Maxpool前;另外三次在通道数变化前。 上采样combine时采用的是插值(nn.functionnal.interpolate)。
全栈程序员站长
2022/11/10
5770
9 大主题卷积神经网络(CNN)的 PyTorch 实现
深度系统介绍了 52 个目标检测模型,纵观 2013 年到 2020 年,从最早的 R-CNN、OverFeat 到后来的 SSD、YOLO v3 再到去年的 M2Det,新模型层出不穷,性能也越来越好!
红色石头
2022/01/20
6760
9 大主题卷积神经网络(CNN)的 PyTorch 实现
PyTorch实现的ResNet50、ResNet101和ResNet152
PyTorch实现的ResNet50、ResNet101和ResNet152 PyTorch: https://github.com/shanglianlm0525/PyTorch-Networks
全栈程序员站长
2022/11/10
9130
PyTorch实现的ResNet50、ResNet101和ResNet152
真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件
所谓“插件”,就是要能锦上添花,又容易植入、落地,即真正的即插即用。本文盘点的“插件”能够提升CNN平移、旋转、scale等变性能力或多尺度特征提取,感受野等能力,在很多SOTA网络中都会看到它们的影子。 >>加入极市CV技术交流群,走在计算机视觉的最前沿
AIWalker
2021/01/18
6780
真正的即插即用!盘点11种CNN网络设计中精巧通用的“小”插件
CVPR2021全新Backbone | ReXNet在CV全任务以超低FLOPs达到SOTA水平(文末下载论文和源码)
本文主要是针对Representational Bottleneck问题进行的讨论,并提出了一套可以显著改善模型性能的设计原则。本文中作者认为在传统网络的设计的中可能会存在Representational Bottleneck问题,并且该问题会导致模型性能的降低。
集智书童公众号
2021/05/28
8500
【YOLOv8】YOLOv8改进系列(6)----替换主干网络之VanillaNet
VanillaNet,是一种强调简洁性和优雅设计的新型神经网络架构。VanillaNet 通过避免深度结构、跳过连接和复杂的操作(如自注意力机制),实现了在计算机视觉任务中与深度复杂网络相当的性能,同时具有更高的效率和可部署性。
HABuo
2025/03/13
1610
【YOLOv8】YOLOv8改进系列(6)----替换主干网络之VanillaNet
卷积神经网络学习路线(二十四)| 华为GhostNet
受限于内存以及计算资源,将常规的CNN架构部署到移动设备是件非常困难的事。近几年来有各种移动端网络架构设计,大部分都是从减少卷积计算量的思路出发,谷歌出品的Mobilenet系列是提出了「Depthwise+Pointwise卷积」来减少计算量,旷视则是提出「通道混洗」,利用转置操作,均匀的shuffle各个通道进行卷积。Mixnet是在Mobilenet基础上,关注了卷积核的大小,通过「不同大小卷积核」所生成的卷积图在不增加计算量前提下进一步提高精度。而华为的Ghostnet则是聚焦于「特征图冗余」,希望通过少量的计算(即论文里的cheap operation)得到大量特征图。而Ghostnet在相同计算量下,精度超越了Mobilenetv3,达到了75.7%分类准确率( ImageNet ILSVRC-2012 classification dataset)
BBuf
2020/06/02
1.1K0
基于卷积神经网络的垃圾分类
自今年7月1日起,上海市将正式实施 《上海市生活垃圾管理条例》。垃圾分类,看似是微不足道的“小事”,实则关系到13亿多人生活环境的改善,理应大力提倡。
云微
2023/02/11
9250
基于卷积神经网络的垃圾分类
涨点神器:基于Yolov8小目标遮挡物性能提升(SEAM、MultiSEAM)
不同的目标检测应用场景有不同的检测难点,小目标、多尺度以及背景复杂等问题,被遮挡的物体仍然是最先进的物体检测器面临的挑战。本文尝试解决待测目标相互遮挡带来的检测困难,对于人脸遮挡提出了一个名为 SEAM 的注意力模块并引入了排斥损失来解决它,引入了分离和增强注意力模块来增强Neck层输出部分后被遮挡人脸的响应能力。
AI小怪兽
2023/11/30
7.2K0
Pytorch实现轻量去雾网络
本文复现了一个轻量级的图像去雾网络,不需要租赁服务器,使用自己的电脑就可以完成模型训练及测试。该网络基于编解码器建立,在编解码部分使用特征增强以改善整体的恢复效果。
Srlua
2024/12/18
1360
Pytorch实现轻量去雾网络
推荐阅读
相关推荐
工程必备!轻量级网络面试题!!
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验