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)