1.Ghostnet、G_ghost、Ghostnetv2性能比较
引入到yolov8,Bottleneck与c2f结合,代替backbone中的所有c2f。
layers | parameters | GFLOPs | kb | |
---|---|---|---|---|
YOLOv8s | 168 | 11125971 | 28.4 | 21991 |
YOLOv8_C2f_GhostBottleneckV2s | 279 | 2553539 | 6.8 | 5250 |
YOLOv8_C2f_GhostBottlenecks | 267 | 2553539 | 6.8 | 5248 |
YOLOv8_C2f_g_ghostBottlenecks | 195 | 2581091 | 6.9 | 5283 |
2.Ghostnet介绍
论文: https://arxiv.org/pdf/1911.11907.pdf
摘要: 由于内存和计算资源的限制,在嵌入式设备商部署卷积神经网络CNN很困难。Deploying convolutional neural networks (CNNs)on embedded devices is difficulty due to the limited memory and computation resources. 特征图中的冗余是成功神经网络的重要特征,但在神经网络架构设计中很少研究,本文提出一种新的Ghost模块,从廉价的操作中生成更多的特征图。基于一组内在的特征图,以低成本应用一系列线性变换来生成许多ghost特征图,可以充分揭示内在特征的信息。所提出的Ghost模块可以作为即插即用的组件轻松升级现有的卷积神经网络,Ghost bottleneck被设计为堆叠Ghost模块 ,然后轻松建立轻量级GhostNet。
在主流的深度神经网络提取的特征图中,丰富甚至冗余的信息通常保证了对输入数据的全面理解。例如,图1展示了由ResNet-50生成的输入图像的一些特征图,并且存在许多相似的特征图对,就像彼此之间的幽灵一样
引入了一个新的 Ghost 模块,通过使用更少的参数来生成更多的特征。具体来说,深度神经网络中的一个普通卷积层会被分成两部分。第一部分涉及普通卷积,但它们的总数将受到严格控制。给定第一部分的内在特征图,然后应用一系列简单的线性操作来生成更多的特征图。在不改变输出特征图的大小的情况下,与普通卷积神经网络相比,这个 Ghost 模块所需的总体参数数量和计算复杂度有所降低。
基于 Ghost 模块,建立了一个高效的神经架构,即 GhostNet。首先替换基准神经架构中的原始卷积层以证明 Ghost 模块的有效性,然后验证 GhostNets 在几个基准视觉数据集上的优越性。
利用ghost模块的优势,介绍了专门为小模型设计Ghost bottlenck,如图3所示。Ghost bottleneck类似于ResNet中基本残差块,其中集成了几个卷积层和shortcuts。ghost bottleneck主要有堆叠的ghost module组成,第一个ghost模块充当增加通道数量的扩展层,将输出通道数和输入通道数之比成为扩展比。第二个ghost模块减少通道数量以匹配shortcuts,然后,shortcuts在这两个ghost模块的输入和输出之间。BN和ReLu在每一层之后应用,第二个ghost模块后不用ReLU。
实验结果表明,所提出的 Ghost 模块能够降低通用卷积层的计算成本,同时保持相似的识别性能,并且 GhostNets 可以在各种任务上超越SOTA高效深度模型,如 MobileNetV3 移动设备上的快速推理。
3.Yolov8引入Ghostnet
3.1 加入ultralytics/nn/backbone/ghostnet.py
核心代码:
代码语言:javascript复制class GhostNet(nn.Module):
def __init__(self, cfgs, num_classes=1000, width=1.0, dropout=0.2):
super(GhostNet, self).__init__()
# setting of inverted residual blocks
self.cfgs = cfgs
self.dropout = dropout
# building first layer
output_channel = _make_divisible(16 * width, 4)
self.conv_stem = nn.Conv2d(3, output_channel, 3, 2, 1, bias=False)
self.bn1 = nn.BatchNorm2d(output_channel)
self.act1 = nn.ReLU(inplace=True)
input_channel = output_channel
# building inverted residual blocks
stages = []
block = GhostBottleneck
for cfg in self.cfgs:
layers = []
for k, exp_size, c, se_ratio, s in cfg:
output_channel = _make_divisible(c * width, 4)
hidden_channel = _make_divisible(exp_size * width, 4)
layers.append(block(input_channel, hidden_channel, output_channel, k, s,
se_ratio=se_ratio))
input_channel = output_channel
stages.append(nn.Sequential(*layers))
output_channel = _make_divisible(exp_size * width, 4)
stages.append(nn.Sequential(ConvBnAct(input_channel, output_channel, 1)))
input_channel = output_channel
self.blocks = nn.Sequential(*stages)
# building last several layers
output_channel = 1280
self.global_pool = nn.AdaptiveAvgPool2d((1, 1))
self.conv_head = nn.Conv2d(input_channel, output_channel, 1, 1, 0, bias=True)
self.act2 = nn.ReLU(inplace=True)
self.classifier = nn.Linear(output_channel, num_classes)
self.channel = [i.size(-1) for i in self.forward(torch.randn(1, 3, 640, 640))]
def forward(self, x):
x = self.conv_stem(x)
x = self.bn1(x)
x = self.act1(x)
x = self.blocks(x)
x = self.global_pool(x)
x = self.conv_head(x)
x = self.act2(x)
x = x.view(x.size(0), -1)
if self.dropout > 0.:
x = F.dropout(x, p=self.dropout, training=self.training)
x = self.classifier(x)
return x
def ghostnet(**kwargs):
"""
Constructs a GhostNet model
"""
cfgs = [
# k, t, c, SE, s
# stage1
[[3, 16, 16, 0, 1]],
# stage2
[[3, 48, 24, 0, 2]],
[[3, 72, 24, 0, 1]],
# stage3
[[5, 72, 40, 0.25, 2]],
[[5, 120, 40, 0.25, 1]],
# stage4
[[3, 240, 80, 0, 2]],
[[3, 200, 80, 0, 1],
[3, 184, 80, 0, 1],
[3, 184, 80, 0, 1],
[3, 480, 112, 0.25, 1],
[3, 672, 112, 0.25, 1]
],
# stage5
[[5, 672, 160, 0.25, 2]],
[[5, 960, 160, 0, 1],
[5, 960, 160, 0.25, 1],
[5, 960, 160, 0, 1],
[5, 960, 160, 0.25, 1]
]
]
return GhostNet(cfgs, **kwargs)
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!