Введенный в yolov8, Bottleneck объединен с c2f, заменяя все 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 |
бумага:https://arxiv.org/pdf/2211.12905.pdf
Хотя модуль Ghost может значительно снизить вычислительные затраты, его возможности представления функций также ослаблены, поскольку «операция свертки может моделировать только локальную информацию внутри окна». В GhostNet пространственная информация половины объектов захватывается с помощью дешевых операций (глубинная свертка 3×3), а остальные объекты получаются только с помощью поточечной свертки 1×1, без какой-либо информации, связанной с другими пикселями. общаться. Способность захвата пространственной информации слаба, что может препятствовать дальнейшему улучшению производительности. Работа GhostNetV2, представленная в этой статье, представляет собой расширенную версию GhostNet, принятую в качестве Spotlight в NeurIPS 2022.
DFC Attention: Модуль внимания на основе разделенного полносвязного слоя
Модуль внимания, подходящий для небольших торцевых моделей, должен отвечать трем условиям:
На рисунке 4 ниже схематически показано узкое место GhostV2. Ветка внимания DFC расположена параллельно первому модулю Ghost для расширения расширенных функций. Расширенные функции затем вводятся во второй модуль Ghost для создания выходных функций. Он фиксирует зависимость между пикселями на больших расстояниях в разных пространственных положениях и повышает выразительность модели.
основной код
class GhostModuleV2(nn.Module):
def __init__(self, inp, oup, kernel_size=1, ratio=2, dw_size=3, stride=1, relu=True, mode=None, args=None):
super(GhostModuleV2, self).__init__()
self.mode = mode
self.gate_fn = nn.Sigmoid()
if self.mode in ['original']:
self.oup = oup
init_channels = math.ceil(oup / ratio)
new_channels = init_channels * (ratio - 1)
self.primary_conv = nn.Sequential(
nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size // 2, bias=False),
nn.BatchNorm2d(init_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
self.cheap_operation = nn.Sequential(
nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size // 2, groups=init_channels, bias=False),
nn.BatchNorm2d(new_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
elif self.mode in ['attn']:
self.oup = oup
init_channels = math.ceil(oup / ratio)
new_channels = init_channels * (ratio - 1)
self.primary_conv = nn.Sequential(
nn.Conv2d(inp, init_channels, kernel_size, stride, kernel_size // 2, bias=False),
nn.BatchNorm2d(init_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
self.cheap_operation = nn.Sequential(
nn.Conv2d(init_channels, new_channels, dw_size, 1, dw_size // 2, groups=init_channels, bias=False),
nn.BatchNorm2d(new_channels),
nn.ReLU(inplace=True) if relu else nn.Sequential(),
)
self.short_conv = nn.Sequential(
nn.Conv2d(inp, oup, kernel_size, stride, kernel_size // 2, bias=False),
nn.BatchNorm2d(oup),
nn.Conv2d(oup, oup, kernel_size=(1, 5), stride=1, padding=(0, 2), groups=oup, bias=False),
nn.BatchNorm2d(oup),
nn.Conv2d(oup, oup, kernel_size=(5, 1), stride=1, padding=(2, 0), groups=oup, bias=False),
nn.BatchNorm2d(oup),
)
def forward(self, x):
if self.mode in ['original']:
x1 = self.primary_conv(x)
x2 = self.cheap_operation(x1)
out = torch.cat([x1, x2], dim=1)
return out[:, :self.oup, :, :]
elif self.mode in ['attn']:
res = self.short_conv(F.avg_pool2d(x, kernel_size=2, stride=2))
x1 = self.primary_conv(x)
x2 = self.cheap_operation(x1)
out = torch.cat([x1, x2], dim=1)
return out[:, :self.oup, :, :] * F.interpolate(self.gate_fn(res), size=(out.shape[-2], out.shape[-1]),
mode='nearest')
Подробности см.:
https://cv2023.blog.csdn.net/article/details/131300994