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

简介
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一头
而作为提取图像特征的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通过将梯度的变化从头到尾地集成到特征图中,在减少了计算量的同时可以保证准确率。
效果如何
直接看图
可以看到在分类任务中计算量大量下降的同时,精度能够基本保持不变或略有提升
但是在目标检测中
在相同FPS的情况下检测精度大幅上升,只能说,杀疯了!!!! 我们一般称这种网络为
网怪!
CSP解决了什么问题呢?
增强CNN的学习能力,能够在轻量化的同时保持准确性。降低计算瓶颈降低内存成本怎么实现
在论文中作者一共提出了四种结构分别是DenseNet 、CSPDenseNet 、Fusion First 、Fusion Last
第一个就是普通的网络
Fusion First的方式是对两个分支的feature map先进行concatenation操作,这样梯度信息可以被重用。
Fusion Last的方式是对Dense Block所在分支先进性transition操作,然后再进行concatenation, 梯度信息将被截断,因此不会重复使用梯度信息 。
经过图像对比可知,Fusion Frist 与Fusion Last都能起到减少计算量的工作,但是对于精度的提升帮助就比较鸡肋了
但是同时使用Fusion First和Fusion Last的CSP所采用的融合方式可以在降低计算代价的同时,提升准确率。
ResNet讲解
ResNet太过经典了这里就不做过多介绍了 有兴趣可以去网上自行搜索
同时--光速吟唱 有兴趣可以看一下我写的ResNet+FPN详解
CSPResNet
就像ResNet与DarkNet有一个最基础的部分,CSPResNet也有最基础的测部分,而这个最基础的部分就是ConvBNLayer
ConvBNLayer部分
可以看到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结构
可以发现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分支构成,并将两者分支输出相加之后再经过激活函数
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叠加而成的网络
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形式的网络
首先会先计算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## https://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很漂亮,但是它不是工艺品,它是需要被拿来用的。
相关攻略
常见报错解析:“Access Not Configured”故障排除指南 许多开发者和团队成员在使用OpenClaw集成飞书时,都曾遭遇过一个典型的中断提示:“access not configured”(访问未配置)。该提示会明确显示您的飞书账户ID及一组唯一的配对验证码,并指出需要联系机器人所有
OpenClaw 常用指令大全与使用详解 openclaw status:此命令是查看OpenClaw系统整体健康状态的核心指令,执行后即获取服务运行状况的全面报告,是日常运维的首要诊断工具。 openclaw gateway restart:在修改网关配置后,必须运行此指令以重启网关服务,使配置文
如何通过 OpenClaw 实现 Chrome 浏览器自动化操控 在软件开发与自动化测试领域,持续学习是常态。本文旨在详细介绍如何利用 OpenClaw 连接并控制一个已开启的 Chrome 浏览器实例,实现点击、文本输入、文件上传、页面滚动、屏幕截图以及执行 JavaScript 等自动化操作。整
项目概述 你是否希望将强大的 AI 助手带入日常聊天?本教程将指导你完成搭建流程,让你能在 QQ 上直接调用 OpenClaw 智能助手,实现无门槛的 AI 对话体验。 架构说明 ┌─────────────┐ ┌──────────────┐ ┌─────────────┐ │ QQ 用户 │ ─
一 下载并安装Node js,全程保持默认设置 首先,请前往Node js官方网站的下载中心:https: nodejs org zh-cn download。根据您的操作系统(Windows Mac Linux)下载对应的安装程序。运行安装向导时,整个过程非常简单,您只需连续点击“下一步”按钮
热门专题
热门推荐
成就解锁全面解析 想要成功解锁“检疫区最后一站麻烦事”成就,玩家需要在危机四伏的检疫区核心地带,精准完成一系列高难度任务流程。这不仅是技术的考验,更是对地图理解、资源管理与临场决策的综合挑战。 前期充分准备 进入检疫区前,周密的战前准备是成功的一半。务必确保武器性能优良,配备足量的弹药与医疗物资。强
Filecoin (FIL) 价格暴涨超70%突破2美元!2025冲击3美元深度解析与长线预测 过去24小时,加密货币市场见证了一场来自去中心化存储龙头Filecoin (FIL)的逆势狂飙。FIL价格从约1 33美元强势拉升至2 25美元上方,单日涨幅突破70%,不仅成功收复关键阻力位,更一举登上
一、浩劫恶魔猎手天赋深度解析 面对《魔兽世界》12 0前夕版本全新的天赋树,浩劫恶魔猎手玩家急需一套高效的加点方案。如何精准配置天赋,将这张复杂的“天赋蓝图”转化为极致的实战输出?本文将深入剖析12 0前夕浩劫DH的核心天赋选择逻辑与加点路线,助你手中的战刃发挥出毁灭性的威力。 二、核心天赋层级详解
欧易通行密钥全攻略:告别传统密码,构建Web3级安全防线 在数字资产安全日益受到挑战的今天,传统密码的脆弱性暴露无遗。网络钓鱼、数据泄露等威胁迫使我们必须采用更前沿的身份验证方案。作为全球领先的Web3科技公司,欧易OKX推出的通行密钥功能,正是基于FIDO2国际安全标准的无密码登录解决方案。本文将
刀法流派核心特点解析 江湖广阔,武学纷呈。《下一站江湖2》中的刀法流派体系丰富,风格鲜明,为武者提供了多样化的成长路径。部分流派崇尚绝对力量,追求瞬间的高额爆发,力求一击制胜;另有流派则注重持久与掌控,刀势如连绵江水,以稳定的高频输出主导战场节奏。深入了解各刀法流派的核心机制与特点,是选择最适合自身





