1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| import torch import torch.nn as nn
class LocalGlobalAttention(nn.Module): """局部-全局注意力模块""" def __init__(self, in_channels: int, reduction: int = 4): super().__init__() self.local_conv = nn.Sequential( nn.Conv2d(in_channels, in_channels // reduction, 3, padding=1), nn.BatchNorm2d(in_channels // reduction), nn.ReLU(inplace=True), nn.Conv2d(in_channels // reduction, in_channels, 1), ) self.global_pool = nn.AdaptiveAvgPool2d(1) self.global_fc = nn.Sequential( nn.Linear(in_channels, in_channels // reduction), nn.ReLU(inplace=True), nn.Linear(in_channels // reduction, in_channels), nn.Sigmoid() ) self.fusion_weight = nn.Parameter(torch.tensor(0.5)) def forward(self, x): """ Args: x: 输入特征 (B, C, H, W) Returns: attended: 注意力增强后的特征 """ B, C, H, W = x.shape local_attn = self.local_conv(x) global_feat = self.global_pool(x).view(B, C) global_attn = self.global_fc(global_feat).view(B, C, 1, 1) alpha = torch.sigmoid(self.fusion_weight) attended = alpha * local_attn + (1 - alpha) * x * global_attn return attended
class KPGBeltNet(nn.Module): """KPGBeltNet 完整网络""" def __init__(self, backbone: str = 'resnet50', num_classes: int = 3): super().__init__() self.backbone = self._build_backbone(backbone) self.kgs = KeypointGuidedSampling() self.lga = LocalGlobalAttention(2048) self.classifier = nn.Sequential( nn.Linear(2048, 512), nn.ReLU(inplace=True), nn.Dropout(0.5), nn.Linear(512, num_classes) ) def forward(self, x, keypoints=None): """ Args: x: 输入图像 (B, 3, H, W) keypoints: 人体关键点(可选) Returns: logits: 安全带状态分类 """ features = self.backbone(x) if keypoints is not None: sampled_features = self.kgs.sample_around_keypoints( features, keypoints, radius=16 ) features = self._fuse_sampled_features(features, sampled_features) attended = self.lga(features) pooled = attended.mean(dim=[2, 3]) logits = self.classifier(pooled) return logits def _fuse_sampled_features(self, global_feat, sampled_feats): """融合全局和采样特征""" fused = global_feat for sf in sampled_feats: upsampled = F.interpolate(sf.unsqueeze(0), size=global_feat.shape[2:], mode='bilinear') fused = fused + upsampled.squeeze(0) return fused
|