You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.6 KiB
Python
82 lines
2.6 KiB
Python
import torch
|
|
import torch.nn as nn
|
|
import ultralytics.nn.modules as um
|
|
import ultralytics.nn.tasks as ut
|
|
import sys
|
|
|
|
|
|
class ChannelAttentionDyn(nn.Module):
|
|
def __init__(self, reduction=16):
|
|
super().__init__()
|
|
self.reduction = reduction
|
|
self.avg_pool = nn.AdaptiveAvgPool2d(1)
|
|
self.max_pool = nn.AdaptiveMaxPool2d(1)
|
|
self.mlp = None
|
|
self.sigmoid = nn.Sigmoid()
|
|
|
|
def _build(self, c, device, dtype):
|
|
hidden = max(c // self.reduction, 1)
|
|
self.mlp = nn.Sequential(
|
|
nn.Conv2d(c, hidden, 1, bias=False),
|
|
nn.ReLU(inplace=True),
|
|
nn.Conv2d(hidden, c, 1, bias=False),
|
|
).to(device=device, dtype=dtype)
|
|
|
|
def forward(self, x):
|
|
if self.mlp is None:
|
|
self._build(x.shape[1], x.device, x.dtype)
|
|
else:
|
|
p = next(self.mlp.parameters())
|
|
if p.device != x.device or p.dtype != x.dtype:
|
|
self.mlp = self.mlp.to(device=x.device, dtype=x.dtype)
|
|
|
|
a = self.mlp(self.avg_pool(x))
|
|
m = self.mlp(self.max_pool(x))
|
|
return x * self.sigmoid(a + m)
|
|
|
|
|
|
class SpatialAttention(nn.Module):
|
|
def __init__(self, kernel_size=7):
|
|
super().__init__()
|
|
padding = kernel_size // 2
|
|
self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
|
|
self.sigmoid = nn.Sigmoid()
|
|
|
|
def forward(self, x):
|
|
if self.conv.weight.device != x.device or self.conv.weight.dtype != x.dtype:
|
|
self.conv = self.conv.to(device=x.device, dtype=x.dtype)
|
|
|
|
avg = torch.mean(x, dim=1, keepdim=True)
|
|
mx, _ = torch.max(x, dim=1, keepdim=True)
|
|
w = self.sigmoid(self.conv(torch.cat([avg, mx], dim=1)))
|
|
return x * w
|
|
|
|
|
|
class CBAM(nn.Module):
|
|
def __init__(self, reduction=16, sa_kernel=7):
|
|
super().__init__()
|
|
self.ca = ChannelAttentionDyn(reduction=reduction)
|
|
self.sa = SpatialAttention(kernel_size=sa_kernel)
|
|
|
|
def forward(self, x):
|
|
return self.sa(self.ca(x))
|
|
|
|
|
|
# Register so torch/ultralytics can deserialize CBAM checkpoints.
|
|
um.CBAM = CBAM
|
|
ut.CBAM = CBAM
|
|
um.ChannelAttentionDyn = ChannelAttentionDyn
|
|
ut.ChannelAttentionDyn = ChannelAttentionDyn
|
|
um.SpatialAttention = SpatialAttention
|
|
ut.SpatialAttention = SpatialAttention
|
|
globals()["ChannelAttentionDyn"] = ChannelAttentionDyn
|
|
globals()["SpatialAttention"] = SpatialAttention
|
|
globals()["CBAM"] = CBAM
|
|
|
|
# Compatibility for checkpoints serialized with __main__.CBAM
|
|
main_mod = sys.modules.get("__main__")
|
|
if main_mod is not None:
|
|
setattr(main_mod, "ChannelAttentionDyn", ChannelAttentionDyn)
|
|
setattr(main_mod, "SpatialAttention", SpatialAttention)
|
|
setattr(main_mod, "CBAM", CBAM)
|