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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202
| """ CNN-BiLSTM混合架构实现
CNN: 提取每帧的空间特征(面部关键点/姿态) BiLSTM: 建模帧间时序依赖(行为序列) 注意力: 加权关键帧(如分心瞬间)
知识迁移: 1. 源域:轿车DMS数据(大量,如StateFarm/DDD数据集) 2. 目标域:电动公交车(少量) 3. 迁移策略:预训练CNN→微调BiLSTM """
import torch import torch.nn as nn from typing import Tuple
class CNNBiLSTMDistraction(nn.Module): """ CNN-BiLSTM分心驾驶检测框架 输入: 视频帧序列 (B, T, C, H, W) 输出: 分心类别概率 (B, n_classes) 参数: 可配置CNN骨干和LSTM隐藏维度 """ def __init__( self, n_classes: int = 5, cnn_backbone: str = "mobilenet_v3_small", lstm_hidden: int = 256, lstm_layers: int = 2, dropout: float = 0.3, ): super().__init__() self.n_classes = n_classes if cnn_backbone == "mobilenet_v3_small": import torchvision.models as models backbone = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights.DEFAULT) self.cnn = nn.Sequential(*list(backbone.children())[:-1]) cnn_out = 576 else: self.cnn = nn.Sequential( nn.Conv2d(3, 32, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(32, 64, 3, stride=2, padding=1), nn.ReLU(), nn.Conv2d(64, 128, 3, stride=2, padding=1), nn.ReLU(), nn.AdaptiveAvgPool2d(1), ) cnn_out = 128 self.lstm = nn.LSTM( input_size=cnn_out, hidden_size=lstm_hidden, num_layers=lstm_layers, batch_first=True, bidirectional=True, dropout=dropout if lstm_layers > 1 else 0, ) self.attention = nn.Sequential( nn.Linear(lstm_hidden * 2, lstm_hidden), nn.Tanh(), nn.Linear(lstm_hidden, 1), ) self.classifier = nn.Sequential( nn.Linear(lstm_hidden * 2, 128), nn.ReLU(), nn.Dropout(dropout), nn.Linear(128, n_classes), ) def forward(self, x: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]: """ Args: x: (B, T, C, H, W) 视频帧序列 Returns: logits: (B, n_classes) 分类结果 attention_weights: (B, T) 注意力权重 """ B, T, C, H, W = x.shape x = x.view(B * T, C, H, W) features = self.cnn(x) features = features.view(B, T, -1) lstm_out, _ = self.lstm(features) attn_weights = self.attention(lstm_out) attn_weights = torch.softmax(attn_weights, dim=1) weighted = (lstm_out * attn_weights).sum(dim=1) logits = self.classifier(weighted) return logits, attn_weights.squeeze(-1)
class KnowledgeTransfer: """ 知识迁移策略 源域: 轿车DMS数据集(大量) 目标域: 电动公交车数据(少量) 迁移方法: Fine-tuning with frozen CNN 1. 在源域数据上预训练CNN-BiLSTM 2. 冻结CNN,在目标域数据上微调BiLSTM 3. 可选:渐进式解冻CNN最后几层 """ def __init__(self, model: CNNBiLSTMDistraction): self.model = model def stage1_pretrain(self, source_data, epochs=50): """Stage 1: 在轿车数据上预训练""" print("Stage 1: 在源域(轿车)数据上预训练") for param in self.model.parameters(): param.requires_grad = True def stage2_finetune(self, target_data, epochs=20): """Stage 2: 在公交车数据上微调""" print("Stage 2: 在目标域(公交车)数据上微调") for param in self.model.cnn.parameters(): param.requires_grad = False trainable = [ p for p in self.model.parameters() if p.requires_grad ] print(f" 可训练参数: {sum(p.numel() for p in trainable):,}") print(f" 冻结参数: {sum(p.numel() for p in self.model.cnn.parameters()):,}") def stage3_progressive_unfreeze(self, target_data, epochs=10): """Stage 3: 渐进式解冻CNN最后层""" print("Stage 3: 渐进式解冻") for param in list(self.model.cnn.parameters())[-4:]: param.requires_grad = True
if __name__ == "__main__": model = CNNBiLSTMDistraction( n_classes=5, cnn_backbone="simple", lstm_hidden=128, lstm_layers=2, ) total_params = sum(p.numel() for p in model.parameters()) print(f"=== CNN-BiLSTM分心检测模型 ===") print(f"总参数: {total_params:,}") batch_size = 4 seq_len = 30 x = torch.randn(batch_size, seq_len, 3, 64, 64) logits, attn = model(x) print(f"\n输入: {x.shape} (B, T, C, H, W)") print(f"输出: {logits.shape} (B, n_classes)") print(f"注意力: {attn.shape} (B, T)") classes = ['正常驾驶', '手机使用', '交谈分心', '疲劳', '其他'] probs = torch.softmax(logits, dim=-1) for i in range(batch_size): pred = classes[probs[i].argmax()] conf = probs[i].max().item() print(f" 样本{i}: {pred} ({conf:.1%})") print(f"\n=== 知识迁移策略 ===") transfer = KnowledgeTransfer(model) transfer.stage1_pretrain(None) transfer.stage2_finetune(None) transfer.stage3_progressive_unfreeze(None) print(f"\n=== 商用车辆DMS特殊性 ===") print(f" 轿车DMS: 个体驾驶、多样场景、大量数据") print(f" 公交DMS: 职业驾驶员、固定路线、少量数据") print(f" 迁移价值: 轿车数据预训练→公交场景微调") print(f" 挑战: 摄像头位置不同、驾驶员坐姿不同、光照不同")
|