当前位置: 首页
AI资讯
PPYOLOE解析1 Backbone

PPYOLOE解析1 Backbone

热心网友 时间:2025-07-25
转载
PP-YOLOE是基于PP-YOLOv2的单阶段Anchor-free模型,含s/m/l/x系列,以CSPResNet为Backbone。CSPResNet融合CSPNet与ResNet,CSPNet通过特殊结构减少计算量并保持精度,解决传统残差网络梯度重复问题。文中还详解了CSPResNet各组成部分结构与代码,并提及BML平台使用体验。

ppyoloe解析1 backbone - 游乐网

简介

PP-YOLOE是基于PP-YOLOv2的卓越的单阶段Anchor-free模型,超越了多种流行的yolo模型。PP-YOLOE有一系列的模型,即s/m/l/x,可以通过width multiplier和depth multiplier配置。PP-YOLOE避免使用诸如deformable convolution或者matrix nms之类的特殊算子,以使其能轻松地部署在多种多样的硬件上。

PP-YOLOE 与其他网络比较

在coco评价上 PPYOLOE成功超越ppyolov2 甚至还压了同样采用anchor-free算法的YOLO-X一头PPYOLOE解析1 Backbone - 游乐网        

而作为提取图像特征的Backbone,PPYOLOE把将SCP结构加入到了ResNet中,形成了CSPResNEt

????什么你说你不懂什么是Backbone?没问题!!!

引用知乎大神 连诗路 Backbone 翻译为主干网络的意思,既然说是主干网络,就代表其是网络的一部分,那么是哪部分呢?翻译的很好,主干部分,哈哈哈哈,文字游戏了哈。这个主干网络大多时候指的是提取特征的网络,其作用就是提取图片中的信息,共后面的网络使用。这些网络经常使用的是resnet VGG等,而不是我们自己设计的网络,因为这些网络已经证明了在分类等问题上的特征提取能力是很强的。在用这些网络作为backbone的时候,都是直接加载最新已经训练好的模型参数,后面接着我们自己的网络。让网络的这两个部分同时进行训练,因为加载的backbone模型已经具有提取特征的能力了,在我们的训练过程中,会对他进行微调,使得其更适合于我们自己的任务。

那么什么是Backbone介绍完了,那么我们就来正式介绍一下CSPResNet !!

网络概述

CSPNet全称是Cross Stage Partial Network,主要从一个比较特殊的角度切入,能够在降低20%计算量的情况下保持甚至提高CNN的能力。

CSP详解

这里我们采用一问一答的形式来进行描述

Cross Stage Partial Network的设计目的?

从网络结构设计的角度来解决以往工作在推理过程中需要很大计算量的问题

为什么传统的残差网络计算量高

作者认为推理计算过高的问题是由于网络优化中的梯度信息重复导致。

如何解决这一问题

CSPNet通过将梯度的变化从头到尾地集成到特征图中,在减少了计算量的同时可以保证准确率。

效果如何

直接看图

PPYOLOE解析1 Backbone - 游乐网        

可以看到在分类任务中计算量大量下降的同时,精度能够基本保持不变或略有提升

但是在目标检测中 PPYOLOE解析1 Backbone - 游乐网        

在相同FPS的情况下检测精度大幅上升,只能说,杀疯了!!!! 我们一般称这种网络为

网怪!

CSP解决了什么问题呢?

增强CNN的学习能力,能够在轻量化的同时保持准确性。降低计算瓶颈降低内存成本

怎么实现

在论文中作者一共提出了四种结构分别是DenseNet 、CSPDenseNet 、Fusion First 、Fusion Last

PPYOLOE解析1 Backbone - 游乐网        

第一个就是普通的网络

Fusion First的方式是对两个分支的feature map先进行concatenation操作,这样梯度信息可以被重用。

Fusion Last的方式是对Dense Block所在分支先进性transition操作,然后再进行concatenation, 梯度信息将被截断,因此不会重复使用梯度信息 。PPYOLOE解析1 Backbone - 游乐网        

经过图像对比可知,Fusion Frist 与Fusion Last都能起到减少计算量的工作,但是对于精度的提升帮助就比较鸡肋了

但是同时使用Fusion First和Fusion Last的CSP所采用的融合方式可以在降低计算代价的同时,提升准确率。

ResNet讲解

ResNet太过经典了这里就不做过多介绍了 有兴趣可以去网上自行搜索

同时--光速吟唱 有兴趣可以看一下我写的ResNet+FPN详解

CSPResNet

就像ResNet与DarkNet有一个最基础的部分,CSPResNet也有最基础的测部分,而这个最基础的部分就是ConvBNLayer

ConvBNLayer部分

PPYOLOE解析1 Backbone - 游乐网        

可以看到ConvBNLayer就是又一个Conv2D与一个BatchNrom2D组成,最后再加上一个激活函数

class ConvBNLayer(nn.Layer):    def __init__(self,                 ch_in,                 ch_out,                 filter_size=3,                 stride=1,                 groups=1,                 padding=0,                 act=None):        super(ConvBNLayer, self).__init__()        self.conv = nn.Conv2D(            in_channels=ch_in,            out_channels=ch_out,            kernel_size=filter_size,            stride=stride,            padding=padding,            groups=groups,            bias_attr=False)        self.bn = nn.BatchNorm2D(            ch_out,            weight_attr=ParamAttr(regularizer=L2Decay(0.0)),            bias_attr=ParamAttr(regularizer=L2Decay(0.0)))        self.act = get_act_fn(act) if act is None or isinstance(act, (            str, dict)) else act    def forward(self, x):        x = self.conv(x)        x = self.bn(x)        x = self.act(x)        return x
登录后复制        

BasicBlock结构

PPYOLOE解析1 Backbone - 游乐网        

可以发现BasicBlock就是使用一个ConvNBLayer加一个RepVggBlock ,既然这里提到了REPVGGBlock那就简单提一下

RepVggBlock结构

RepVGG是一个简单但功能强大的卷积神经网络架构,它具有类似 VGG 的推理时间,仅由一堆 3 × 3 卷积和 ReLU 组成,而训练时间模型具有多分支拓扑。 这种训练期间和推理期间架构的解耦是通过结构重新参数化技术实现的。在 ImageNet 上,RepVGG 达到了超过 80% 的 top-1 准确率,这是plain结构模型的第一次。 在 NVIDIA 1080Ti GPU 上,RepVGG 模型的运行速度比 ResNet-50 快 83% 或比 ResNet-101 快 101%,具有更高的准确度,并且与 EfficientNet 和 RegNet 等最先进的模型相比显示出有利的准确度-速度权衡。

RepVGGBlock由Conv3x3+bn、Conv1x1+bn、identity分支构成,以上三个分支输出add-wise后(不改变通道数)再使用ReLu

而CSPResNet中的RepVGGBlock则是Conv3x3+bn、Conv1x1+bn分支构成,并将两者分支输出相加之后再经过激活函数

PPYOLOE解析1 Backbone - 游乐网        

class RepVggBlock(nn.Layer):    def __init__(self, ch_in, ch_out, act='relu'):        super(RepVggBlock, self).__init__()        self.ch_in = ch_in        self.ch_out = ch_out        self.conv1 = ConvBNLayer(            ch_in, ch_out, 3, stride=1, padding=1, act=None)        self.conv2 = ConvBNLayer(            ch_in, ch_out, 1, stride=1, padding=0, act=None)        self.act = get_act_fn(act) if act is None or isinstance(act, (            str, dict)) else act    def forward(self, x):        if hasattr(self, 'conv'):            y = self.conv(x)        else:            y = self.conv1(x) + self.conv2(x)        y = self.act(y)        return y
登录后复制        

其实CSPResNet中的RepVGGBlock并不只这些,但是由于剩下的是为了做重参数化的,只会在模型导出的时候调用,因此并不展示。

BasicBlock结构

Basicblock就是一个含有残差网络的由ConvBNLayer和REPVggBlock叠加而成的网络

PPYOLOE解析1 Backbone - 游乐网        

class BasicBlock(nn.Layer):    def __init__(self, ch_in, ch_out, act='relu', shortcut=True):        super(BasicBlock, self).__init__()        assert ch_in == ch_out        self.conv1 = ConvBNLayer(ch_in, ch_out, 3, stride=1, padding=1, act=act)        self.conv2 = RepVggBlock(ch_out, ch_out, act=act)        self.shortcut = shortcut    def forward(self, x):        y = self.conv1(x)        y = self.conv2(y)        if self.shortcut:            return paddle.add(x, y)        else:            return y
登录后复制        

CSPResStage结构

终于到了正题了,CSPResStage就是将传统的可重复残差网络更改为CSP形式的网络

PPYOLOE解析1 Backbone - 游乐网        

首先会先计算mdim ,mdim = (cin+cout)/2 ,如果进行了下采样那么则会使用一个ConvBNLayer将通道数从ci更改为mdim同时下采样两倍,之后分出两个分支,将通道数/2,然后其中一支就是放入到传统的可重复残差网络模块训练,然后将两个分支再深度维度进行concat操作,然后使用EffectiveSELayer模块,最后加入一个ConvBNLayer将通道数从dmin改为cout

class CSPResStage(nn.Layer):    def __init__(self,                 block_fn,                 ch_in,                 ch_out,                 n,                 stride,                 act='relu',                 attn='eca'):        super(CSPResStage, self).__init__()        ch_mid = (ch_in + ch_out) // 2        if stride == 2:            self.conv_down = ConvBNLayer(                ch_in, ch_mid, 3, stride=2, padding=1, act=act)        else:            self.conv_down = None        self.conv1 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)        self.conv2 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)        self.blocks = nn.Sequential(* [            block_fn(                ch_mid // 2, ch_mid // 2, act=act, shortcut=True)            for i in range(n)        ])        if attn:            self.attn = EffectiveSELayer(ch_mid, act='hardsigmoid')        else:            self.attn = None        self.conv3 = ConvBNLayer(ch_mid, ch_out, 1, act=act)    def forward(self, x):        if self.conv_down is not None:            x = self.conv_down(x)        y1 = self.conv1(x)        y2 = self.blocks(self.conv2(x))        y = paddle.concat([y1, y2], axis=1)        if self.attn is not None:            y = self.attn(y)        y = self.conv3(y)        return y
登录后复制    In [ ]
# 完整代码
登录后复制    In [ ]
!git clone -b develop https://gitee.com/paddlepaddle/PaddleDetection.git
登录后复制    In [ ]
%cd PaddleDetection/!python setup.py install!pip install -r requirements.txt
登录后复制    In [ ]
# Copyright (c) 2024 PaddlePaddle Authors. All Rights Reserved.## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at##     http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.from __future__ import absolute_importfrom __future__ import divisionfrom __future__ import print_functionimport paddleimport paddle.nn as nnimport paddle.nn.functional as Ffrom paddle import ParamAttrfrom paddle.regularizer import L2Decay# from ppdet.modeling.ops import get_act_fn# from ppdet.core.workspace import register, serializablefrom ppdet.modeling.ops import get_act_fnfrom ppdet.core.workspace import register, serializablefrom ppdet.modeling.shape_spec import ShapeSpec__all__ = ['CSPResNet', 'BasicBlock', 'EffectiveSELayer', 'ConvBNLayer']class ConvBNLayer(nn.Layer):    def __init__(self,                 ch_in,                 ch_out,                 filter_size=3,                 stride=1,                 groups=1,                 padding=0,                 act=None):        super(ConvBNLayer, self).__init__()        self.conv = nn.Conv2D(            in_channels=ch_in,            out_channels=ch_out,            kernel_size=filter_size,            stride=stride,            padding=padding,            groups=groups,            bias_attr=False)        self.bn = nn.BatchNorm2D(            ch_out,            weight_attr=ParamAttr(regularizer=L2Decay(0.0)),            bias_attr=ParamAttr(regularizer=L2Decay(0.0)))        self.act = get_act_fn(act) if act is None or isinstance(act, (            str, dict)) else act    def forward(self, x):        x = self.conv(x)        x = self.bn(x)        x = self.act(x)        return xclass RepVggBlock(nn.Layer):    def __init__(self, ch_in, ch_out, act='relu'):        super(RepVggBlock, self).__init__()        self.ch_in = ch_in        self.ch_out = ch_out        self.conv1 = ConvBNLayer(            ch_in, ch_out, 3, stride=1, padding=1, act=None)        self.conv2 = ConvBNLayer(            ch_in, ch_out, 1, stride=1, padding=0, act=None)        self.act = get_act_fn(act) if act is None or isinstance(act, (            str, dict)) else act    def forward(self, x):        if hasattr(self, 'conv'):            y = self.conv(x)        else:            y = self.conv1(x) + self.conv2(x)        y = self.act(y)        return y    def convert_to_deploy(self):        if not hasattr(self, 'conv'):            self.conv = nn.Conv2D(                in_channels=self.ch_in,                out_channels=self.ch_out,                kernel_size=3,                stride=1,                padding=1,                groups=1)        kernel, bias = self.get_equivalent_kernel_bias()        self.conv.weight.set_value(kernel)        self.conv.bias.set_value(bias)    def get_equivalent_kernel_bias(self):        kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1)        kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2)        return kernel3x3 + self._pad_1x1_to_3x3_tensor(            kernel1x1), bias3x3 + bias1x1    def _pad_1x1_to_3x3_tensor(self, kernel1x1):        if kernel1x1 is None:            return 0        else:            return nn.functional.pad(kernel1x1, [1, 1, 1, 1])    def _fuse_bn_tensor(self, branch):        if branch is None:            return 0, 0        kernel = branch.conv.weight        running_mean = branch.bn._mean        running_var = branch.bn._variance        gamma = branch.bn.weight        beta = branch.bn.bias        eps = branch.bn._epsilon        std = (running_var + eps).sqrt()        t = (gamma / std).reshape((-1, 1, 1, 1))        return kernel * t, beta - running_mean * gamma / stdclass BasicBlock(nn.Layer):    def __init__(self, ch_in, ch_out, act='relu', shortcut=True):        super(BasicBlock, self).__init__()        assert ch_in == ch_out        self.conv1 = ConvBNLayer(ch_in, ch_out, 3, stride=1, padding=1, act=act)        self.conv2 = RepVggBlock(ch_out, ch_out, act=act)        self.shortcut = shortcut    def forward(self, x):        y = self.conv1(x)        y = self.conv2(y)        if self.shortcut:            return paddle.add(x, y)        else:            return yclass EffectiveSELayer(nn.Layer):    """ Effective Squeeze-Excitation    From `CenterMask : Real-Time Anchor-Free Instance Segmentation` - https://arxiv.org/abs/1911.06667    """    def __init__(self, channels, act='hardsigmoid'):        super(EffectiveSELayer, self).__init__()        self.fc = nn.Conv2D(channels, channels, kernel_size=1, padding=0)        self.act = get_act_fn(act) if act is None or isinstance(act, (            str, dict)) else act    def forward(self, x):        x_se = x.mean((2, 3), keepdim=True)        x_se = self.fc(x_se)        return x * self.act(x_se)class CSPResStage(nn.Layer):    def __init__(self,                 block_fn,                 ch_in,                 ch_out,                 n,                 stride,                 act='relu',                 attn='eca'):        super(CSPResStage, self).__init__()        ch_mid = (ch_in + ch_out) // 2        if stride == 2:            self.conv_down = ConvBNLayer(                ch_in, ch_mid, 3, stride=2, padding=1, act=act)        else:            self.conv_down = None        self.conv1 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)        self.conv2 = ConvBNLayer(ch_mid, ch_mid // 2, 1, act=act)        self.blocks = nn.Sequential(* [            block_fn(                ch_mid // 2, ch_mid // 2, act=act, shortcut=True)            for i in range(n)        ])        if attn:            self.attn = EffectiveSELayer(ch_mid, act='hardsigmoid')        else:            self.attn = None        self.conv3 = ConvBNLayer(ch_mid, ch_out, 1, act=act)    def forward(self, x):        if self.conv_down is not None:            x = self.conv_down(x)        y1 = self.conv1(x)        y2 = self.blocks(self.conv2(x))        y = paddle.concat([y1, y2], axis=1)        if self.attn is not None:            y = self.attn(y)        y = self.conv3(y)        return y# @register# @serializableclass CSPResNet(nn.Layer):    __shared__ = ['width_mult', 'depth_mult', 'trt']    def __init__(self,                 layers=[3, 6, 6, 3],                 channels=[64, 128, 256, 512, 1024],                 act='swish',                 return_idx=[0, 1, 2, 3, 4],                 depth_wise=False,                 use_large_stem=False,                 width_mult=1.0,                 depth_mult=1.0,                 trt=False):        super(CSPResNet, self).__init__()        channels = [max(round(c * width_mult), 1) for c in channels]        layers = [max(round(l * depth_mult), 1) for l in layers]        act = get_act_fn(            act, trt=trt) if act is None or isinstance(act,                                                       (str, dict)) else act        if use_large_stem:            self.stem = nn.Sequential(                ('conv1', ConvBNLayer(                    3, channels[0] // 2, 3, stride=2, padding=1, act=act)),                ('conv2', ConvBNLayer(                    channels[0] // 2,                    channels[0] // 2,                    3,                    stride=1,                    padding=1,                    act=act)), ('conv3', ConvBNLayer(                        channels[0] // 2,                        channels[0],                        3,                        stride=1,                        padding=1,                        act=act)))        else:            self.stem = nn.Sequential(                ('conv1', ConvBNLayer(                    3, channels[0] // 2, 3, stride=2, padding=1, act=act)),                ('conv2', ConvBNLayer(                    channels[0] // 2,                    channels[0],                    3,                    stride=1,                    padding=1,                    act=act)))        n = len(channels) - 1        self.stages = nn.Sequential(* [(str(i), CSPResStage(            BasicBlock, channels[i], channels[i + 1], layers[i], 2, act=act))                                       for i in range(n)])        self._out_channels = channels[1:]        self._out_strides = [4, 8, 16, 32]        self.return_idx = return_idx    def forward(self, inputs):        #x = inputs['image']        x = inputs        x = self.stem(x)        outs = []        for idx, stage in enumerate(self.stages):            x = stage(x)            if idx in self.return_idx:                outs.append(x)        return x    @property    def out_shape(self):        return [            ShapeSpec(                channels=self._out_channels[i], stride=self._out_strides[i])            for i in self.return_idx        ]if __name__=='__main__':    model = CSPResNet()    paddle.summary(model,(1,3,640,640))
登录后复制    

结束语

这次我不想聊别的只想说一下关于新版BML的问题,当新版BML没上线的时候,我是抱着满心期待的,尤其是当BML发布之后真的给我惊艳到了,耐看的配色,丰富的UI设计,尤其是一开始我看到那个资源监控室动态的这个真的是最惊艳到我的地方,我当时就想着能不能在本地也下一个BML,但是后来随着深入使用发现了越来越多的问题,当然新平台刚上线嘛肯定有问题慢慢解决就好了,但是现在应该快一年了吧,结果还是一堆bug,我知道维护新平台很累,bug很多,很难修,但是 一年过去了 我想问一下研发的同学有好多bug从去年就开始提为什么到了今年了还是出现,这个是不是有点太。。。如果是资金的问题,可以开放会员制,我举双手赞成,毕竟平台不是慈善家,我今天把这个事情提出来并不是要去埋怨哪个人或者什么,我只是真的想好好的说一下问题,麻烦能不能去沉下心来一段时间好好优化一下BML,BML很漂亮,但是它不是工艺品,它是需要被拿来用的。


       

来源:https://www.php.cn/faq/1426582.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
北大与字节开源实时长视频生成模型Helios详解

北大与字节开源实时长视频生成模型Helios详解

Helios是什么 在AI视频生成领域,如何兼顾生成速度与画面质量一直是核心挑战。近期,由北京大学联合字节跳动等顶尖团队共同研发的Helios模型,为这一难题提供了突破性的解决方案。这款拥有140亿参数的大模型,仅需单张H100 GPU,就能以高达19 5 FPS的实时速度生成分钟级长视频。其卓越性

时间:2026-05-24 07:54
浪潮信息开源多模态基础模型Yuan3.0 Ultra详解

浪潮信息开源多模态基础模型Yuan3.0 Ultra详解

Yuan3 0 Ultra是什么 在通往通用人工智能的探索中,模型规模与性能往往紧密关联。然而,浪潮信息YuanLab ai团队最新开源的Yuan3 0 Ultra模型,为我们提供了全新的视角。这个总参数量高达1 01万亿的巨型模型,并非盲目追求参数扩张,而是创新地采用了混合专家架构,将每次推理的激

时间:2026-05-24 07:53
OpenAI发布GPT‑5.4旗舰AI模型 专为专业工作场景打造

OpenAI发布GPT‑5.4旗舰AI模型 专为专业工作场景打造

GPT‑5 4是什么 如果说此前的AI模型还停留在“聪明地聊天”,那么GPT-5 4的登场,则标志着AI正式迈入了“可靠地干活”的新阶段。OpenAI将其定位为“专为专业工作设计的最强前沿模型”,这个定义绝非虚言。它首次将高阶推理、专业编程、原生计算机操作、深度网页搜索以及百万级别的上下文处理能力,

时间:2026-05-24 07:53
掌阅科技泡漫平台一站式AI漫剧生成工具详解

掌阅科技泡漫平台一站式AI漫剧生成工具详解

泡漫是什么 如果你留意近两年内容创作领域的变革,会发现一个显著趋势:人工智能正以前所未有的深度重塑内容生产流程。而“泡漫”,正是这股AI浪潮中一个极具代表性的创新平台。 简而言之,泡漫是掌阅科技旗下推出的一站式AI漫剧智能生成平台。其核心目标非常明确——运用前沿AI技术彻底革新漫画与短剧的创作模式,

时间:2026-05-24 07:53
AI面试模拟工具:智能追问与深度解答备考指南

AI面试模拟工具:智能追问与深度解答备考指南

播面是什么 如果你已经厌倦了对海量文字资料进行机械记忆,并在面试关键时刻感到无从说起,那么“播面”这一创新学习模式,或许能为你打开全新的备考视角。简而言之,播面是一个将经典技术面试题目转化为系统化音频课程的知识平台。其核心理念非常清晰:通过聆听,掌握面试精髓。 试想一下,那些涉及Java、Sprin

时间:2026-05-24 07:53
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程