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 torch.nn.functional as F
class TransGazeObject(nn.Module): """ TransGaze-Object: 端到端驾驶员注视物体预测 输入: 驾驶员面部图像 + 交通场景图像 + 场景物体边界框 输出: 注视物体分类(车辆/行人/信号灯/背景等) 架构: 1. 面部编码器: 提取面部+虹膜特征 2. 场景物体编码器: 提取交通物体空间特征 3. Cross-Attention: 面部特征与物体特征交互 4. 分类头: 预测注视物体 """ def __init__(self, n_gaze_objects=6, face_feat_dim=512, object_feat_dim=256, n_heads=8): super().__init__() self.face_encoder = nn.Sequential( nn.Conv2d(3, 64, 7, 2, 3), nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(3, 2, 1), *self._make_res_block(64, 128, 2), *self._make_res_block(128, 256, 2), nn.AdaptiveAvgPool2d(1) ) self.iris_encoder = nn.Sequential( nn.Conv2d(1, 32, 3, 1, 1), nn.BatchNorm2d(32), nn.ReLU(), nn.MaxPool2d(2), nn.Conv2d(32, 64, 3, 1, 1), nn.BatchNorm2d(64), nn.ReLU(), nn.AdaptiveAvgPool2d(1) ) self.face_proj = nn.Linear(256 + 64, face_feat_dim) self.object_encoder = nn.Sequential( nn.Linear(5, 128), nn.ReLU(), nn.Linear(128, object_feat_dim) ) self.cross_attention = nn.MultiheadAttention( embed_dim=face_feat_dim, num_heads=n_heads, kdim=object_feat_dim, vdim=object_feat_dim, batch_first=True ) self.attn_norm = nn.LayerNorm(face_feat_dim) self.classifier = nn.Sequential( nn.Linear(face_feat_dim, 128), nn.ReLU(), nn.Dropout(0.3), nn.Linear(128, n_gaze_objects) ) def _make_res_block(self, in_c, out_c, n_blocks): blocks = [] for _ in range(n_blocks): blocks.extend([ nn.Conv2d(in_c, out_c, 3, 1, 1), nn.BatchNorm2c(out_c), nn.ReLU(), nn.Conv2d(out_c, out_c, 3, 1, 1), nn.BatchNorm2d(out_c), nn.ReLU(), ]) in_c = out_c return blocks def forward(self, face_img, iris_img, object_boxes): """ Args: face_img: (B, 3, 224, 224) 驾驶员面部 iris_img: (B, 1, 64, 64) 虹膜区域 object_boxes: (B, N, 5) 场景物体 [x1,y1,x2,y2,area] Returns: logits: (B, N, n_gaze_objects) 每个物体的注视概率 """ B, N, _ = object_boxes.shape face_feat = self.face_encoder(face_img).flatten(1) iris_feat = self.iris_encoder(iris_img).flatten(1) face_fused = self.face_proj( torch.cat([face_feat, iris_feat], dim=-1) ) obj_feat = self.object_encoder(object_boxes) face_query = face_fused.unsqueeze(1) attn_out, attn_weights = self.cross_attention( face_query, obj_feat, obj_feat ) attn_out = self.attn_norm(face_fused.unsqueeze(1) + attn_out) logits = self.classifier(attn_out.squeeze(1)) all_obj_logits = [] for i in range(N): obj_attn = attn_weights[:, :, i:i+1] obj_feat_i = obj_feat[:, i] * obj_attn.squeeze(-1) obj_logits = self.classifier( face_fused + obj_feat_i ) all_obj_logits.append(obj_logits) return torch.stack(all_obj_logits, dim=1)
UD_FSG_DATASET = { 'name': 'Urban Driving-Face Scene Gaze', 'samples': '~10K synchronized pairs', 'modalities': ['driver_face', 'traffic_scene', 'object_boxes', 'gaze_2d', 'gaze_object'], 'gaze_objects': [ 'vehicle', 'pedestrian', 'traffic_signal', 'road', 'background', 'unknown', ], 'collection': 'real urban driving' }
if __name__ == "__main__": model = TransGazeObject(n_gaze_objects=6) face = torch.randn(4, 3, 224, 224) iris = torch.randn(4, 1, 64, 64) boxes = torch.randn(4, 10, 5) logits = model(face, iris, boxes) print(f"面部: {face.shape}") print(f"虹膜: {iris.shape}") print(f"物体: {boxes.shape}") print(f"输出: {logits.shape} (4×10×6)")
|