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
| class SceneGridAttention(nn.Module): """场景网格注意力模块 将道路场景划分为网格,计算视线意图与每个网格的注意力权重 """ def __init__(self, scene_grid_size=(8, 8), gaze_dim=128, scene_feat_dim=512): super().__init__() self.grid_size = scene_grid_size self.scene_encoder = self._get_backbone('resnet18') self.grid_proj = nn.Linear(scene_feat_dim, 256) self.gaze_proj = nn.Linear(gaze_dim, 256) self.attention = nn.MultiheadAttention( embed_dim=256, num_heads=8, batch_first=True ) self.pog_predictor = nn.Sequential( nn.Linear(256, 128), nn.ReLU(), nn.Linear(128, 2) ) def _get_backbone(self, name): """获取骨干网络""" import torchvision.models as models model = models.resnet18(pretrained=True) model = nn.Sequential(*list(model.children())[:-1]) return model def forward(self, scene_img, gaze_intent): """ Args: scene_img: (B, 3, H, W) 道路场景图像 gaze_intent: (B, 128) 视线意图向量 Returns: pog: (B, 2) 视线落点坐标(归一化) attention_weights: (B, grid_h, grid_w) 注意力权重分布 """ B = scene_img.size(0) scene_feat = self.scene_encoder(scene_img).squeeze(-1).squeeze(-1) grid_h, grid_w = self.grid_size grid_feats = self.grid_proj(scene_feat).unsqueeze(1).expand(B, grid_h * grid_w, -1) gaze_query = self.gaze_proj(gaze_intent).unsqueeze(1) attn_output, attn_weights = self.attention( query=gaze_query, key=grid_feats, value=grid_feats ) pog = self.pog_predictor(attn_output.squeeze(1)) attention_weights = attn_weights.squeeze(1).view(B, grid_h, grid_w) return pog, attention_weights
class SGAPGaze(nn.Module): """SGAP-Gaze完整模型 论文:SGAP-Gaze: Scene Grid Attention Based Point-of-Gaze Estimation """ def __init__(self, config=None): super().__init__() self.config = config or {} self.face_fusion = MultiModalFaceFusion() self.scene_attention = SceneGridAttention() def forward(self, inputs): """ Args: inputs: dict - face: (B, 3, 224, 224) - left_eye: (B, 3, 64, 64) - right_eye: (B, 3, 64, 64) - iris: (B, 3, 32, 32) - scene: (B, 3, H, W) Returns: output: dict - pog: (B, 2) 视线落点 - attention: (B, 8, 8) 注意力分布 """ gaze_intent = self.face_fusion( inputs['face'], inputs['left_eye'], inputs['right_eye'], inputs['iris'] ) pog, attention = self.scene_attention(inputs['scene'], gaze_intent) return { 'pog': pog, 'attention': attention, 'gaze_intent': gaze_intent }
if __name__ == "__main__": model = SGAPGaze() batch_size = 4 inputs = { 'face': torch.randn(batch_size, 3, 224, 224), 'left_eye': torch.randn(batch_size, 3, 64, 64), 'right_eye': torch.randn(batch_size, 3, 64, 64), 'iris': torch.randn(batch_size, 3, 32, 32), 'scene': torch.randn(batch_size, 3, 720, 1280) } output = model(inputs) print(f"视线落点: {output['pog']}") print(f"注意力分布形状: {output['attention'].shape}")
|