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
| class PhysicsGuidedCrossAttention(nn.Module): """ PGCA: 将径向-多普勒一致性和 RCS 物理约束嵌入注意力 论文 Section 3.3: 物理引导的交叉注意力 核心思想: - 径向速度一致性: 雷达测量的径向速度应与查询到点的方向一致 - RCS 相关性: 大 RCS 的雷达点更可能对应真实目标 """ def __init__(self, embed_dim=256, num_heads=8): super().__init__() self.embed_dim = embed_dim self.num_heads = num_heads self.head_dim = embed_dim // num_heads self.q_proj = nn.Linear(embed_dim, embed_dim) self.k_proj = nn.Linear(embed_dim, embed_dim) self.v_proj = nn.Linear(embed_dim, embed_dim) self.physics_proj = nn.Linear(4, num_heads) self.scale = self.head_dim ** -0.5 self.out_proj = nn.Linear(embed_dim, embed_dim) def compute_radial_consistency(self, query_pos, point_pos, point_velocity): """ 计算径向-多普勒一致性 径向速度 = velocity · (point_pos - query_pos) / ||point_pos - query_pos|| Args: query_pos: (Q, 3) 查询位置 point_pos: (N, 3) 雷达点位置 point_velocity: (N, 3) 雷达点速度 Returns: consistency: (Q, N) 径向一致性分数 """ diff = point_pos.unsqueeze(0) - query_pos.unsqueeze(1) dist = torch.norm(diff, dim=-1, keepdim=True).clamp(min=0.1) direction = diff / dist radial_vel = (point_velocity.unsqueeze(0) * direction).sum(dim=-1) measured_speed = torch.norm(point_velocity, dim=-1) consistency = torch.abs(radial_vel) / (measured_speed.unsqueeze(0) + 0.1) consistency = consistency.clamp(0, 1) return consistency def forward(self, query_feat, key_feat, value_feat, query_pos, point_pos, point_velocity, point_rcs): """ Args: query_feat: (Q, D) 查询特征 key_feat: (N, D) 键特征 value_feat: (N, D) 值特征 query_pos: (Q, 3) 查询位置 point_pos: (N, 3) 雷达点位置 point_velocity: (N, 3) 雷达点速度 point_rcs: (N,) 雷达截面积 """ Q, D = query_feat.shape N = key_feat.shape[0] H = self.num_heads q = self.q_proj(query_feat).view(Q, H, self.head_dim).transpose(0, 1) k = self.k_proj(key_feat).view(N, H, self.head_dim).transpose(0, 1) v = self.v_proj(value_feat).view(N, H, self.head_dim).transpose(0, 1) attn = torch.matmul(q, k.transpose(-2, -1)) * self.scale consistency = self.compute_radial_consistency( query_pos, point_pos, point_velocity ) distance = torch.norm( point_pos.unsqueeze(0) - query_pos.unsqueeze(1), dim=-1 ) physics_input = torch.stack([ consistency, point_rcs.unsqueeze(0).expand(Q, -1) / 10.0, 1.0 / (distance + 1.0), torch.norm(point_velocity, dim=-1).unsqueeze(0).expand(Q, -1), ], dim=-1) physics_bias = self.physics_proj(physics_input) physics_bias = physics_bias.permute(2, 0, 1) attn = attn + physics_bias attn = torch.softmax(attn, dim=-1) out = torch.matmul(attn, v) out = out.transpose(0, 1).reshape(Q, D) out = self.out_proj(out) return out
if __name__ == "__main__": pgca = PhysicsGuidedCrossAttention(embed_dim=256, num_heads=8) Q, N, D = 50, 200, 256 query_feat = torch.randn(Q, D) key_feat = torch.randn(N, D) value_feat = torch.randn(N, D) query_pos = torch.randn(Q, 3) point_pos = torch.randn(N, 3) point_vel = torch.randn(N, 3) point_rcs = torch.rand(N) * 10 out = pgca(query_feat, key_feat, value_feat, query_pos, point_pos, point_vel, point_rcs) print(f"PGCA output shape: {out.shape}") print(f"Parameters: {sum(p.numel() for p in pgca.parameters()):,}")
|