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 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
| import torch import torch.nn as nn import numpy as np from dataclasses import dataclass
class ChannelAttention(nn.Module): """通道注意力:聚焦重要特征通道""" def __init__(self, in_channels: int, reduction: int = 16): super().__init__() self.avg_pool = nn.AdaptiveAvgPool2d(1) self.max_pool = nn.AdaptiveMaxPool2d(1) self.fc = nn.Sequential( nn.Conv2d(in_channels, in_channels // reduction, 1), nn.ReLU(), nn.Conv2d(in_channels // reduction, in_channels, 1) ) def forward(self, x): avg_out = self.fc(self.avg_pool(x)) max_out = self.fc(self.max_pool(x)) return torch.sigmoid(avg_out + max_out)
class SpatialAttention(nn.Module): """空间注意力:聚焦关键面部区域""" def __init__(self, kernel_size: int = 7): super().__init__() self.conv = nn.Conv2d(2, 1, kernel_size, padding=kernel_size//2) def forward(self, x): avg_out = torch.mean(x, dim=1, keepdim=True) max_out, _ = torch.max(x, dim=1, keepdim=True) cat = torch.cat([avg_out, max_out], dim=1) return torch.sigmoid(self.conv(cat))
class DualAttentionBlock(nn.Module): """双注意力块:通道+空间""" def __init__(self, in_channels: int): super().__init__() self.ca = ChannelAttention(in_channels) self.sa = SpatialAttention() def forward(self, x): x = x * self.ca(x) x = x * self.sa(x) return x
class LowLightDrowsinessModel(nn.Module): """ 低光照睡意检测模型 架构: 1. 低光照增强预处理 2. CNN骨干+双注意力 3. 分类+Grad-CAM解释 """ def __init__(self, n_classes: int = 3): super().__init__() self.enhance = nn.Sequential( nn.Conv2d(3, 3, 3, padding=1), nn.BatchNorm2d(3), nn.ReLU(), nn.Conv2d(3, 3, 3, padding=1), nn.Sigmoid(), ) self.backbone = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.BatchNorm2d(32), nn.ReLU6(), DualAttentionBlock(32), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.BatchNorm2d(64), nn.ReLU6(), DualAttentionBlock(64), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.BatchNorm2d(128), nn.ReLU6(), DualAttentionBlock(128), nn.AdaptiveAvgPool2d(1), nn.Flatten(), ) self.classifier = nn.Sequential( nn.Linear(128, 64), nn.ReLU(), nn.Dropout(0.2), nn.Linear(64, n_classes) ) self.features = None def forward(self, x): enhanced = self.enhance(x) feat = self.backbone(enhanced) self.features = feat return self.classifier(feat) def grad_cam(self, x, target_class=None): """Grad-CAM可解释性分析""" x.requires_grad_(True) output = self.forward(x) if target_class is None: target_class = output.argmax(dim=1) self.zero_grad() target = output[0, target_class] target.backward() gradients = x.grad heatmap = gradients.abs().mean(dim=1, keepdim=True) heatmap = (heatmap - heatmap.min()) / (heatmap.max() - heatmap.min() + 1e-8) return output, heatmap
if __name__ == "__main__": model = LowLightDrowsinessModel(n_classes=3) normal = torch.randn(1, 3, 96, 96) low_light = torch.randn(1, 3, 96, 96) * 0.3 + 0.1 out_normal = model(normal) out_low = model(low_light) print("=== 低光照睡意检测 ===") print(f"正常光照输出: {out_normal[0]}") print(f"低光照输出: {out_low[0]}") x = torch.randn(1, 3, 96, 96) output, heatmap = model.grad_cam(x) print(f"\nGrad-CAM热力图: {heatmap.shape}") print(f"注意力区域均值: {heatmap.mean():.4f}") params = sum(p.numel() for p in model.parameters()) print(f"\n总参数: {params:,}")
|