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
| import torch import torch.nn as nn
class SpatioTemporalRadarEncoder(nn.Module): """ 时空雷达编码器 捕获体态配置和运动动态 论文 Section 3.1 输入:雷达张量序列 (B, T, C, D_r, D_d, D_a) 输出:时空特征序列 (B, T, hidden) """ def __init__(self, in_channels=4, hidden=256, num_heads=4, num_layers=4): super().__init__() self.spatial_encoder = nn.Sequential( nn.Conv3d(in_channels, hidden // 4, 3, stride=2, padding=1), nn.BatchNorm3d(hidden // 4), nn.ReLU(), nn.Conv3d(hidden // 4, hidden // 2, 3, stride=2, padding=1), nn.BatchNorm3d(hidden // 2), nn.ReLU(), nn.Conv3d(hidden // 2, hidden, 3, stride=2, padding=1), nn.BatchNorm3d(hidden), nn.ReLU(), nn.AdaptiveAvgPool3d(1) ) self.temporal_pos_embed = nn.Parameter(torch.randn(1, 256, hidden)) encoder_layer = nn.TransformerEncoderLayer( d_model=hidden, nhead=num_heads, dim_feedforward=hidden * 4, dropout=0.1, activation='gelu', batch_first=True ) self.temporal_encoder = nn.TransformerEncoder(encoder_layer, num_layers) def forward(self, radar_sequence): """ Args: radar_sequence: (B, T, C, D_r, D_d, D_a) Returns: features: (B, T, hidden) - 时空特征 """ B, T = radar_sequence.shape[:2] spatial_feats = [] for t in range(T): feat = self.spatial_encoder(radar_sequence[:, t]) spatial_feats.append(feat.flatten(1)) spatial_feats = torch.stack(spatial_feats, dim=1) spatial_feats = spatial_feats + self.temporal_pos_embed[:, :T, :] temporal_feats = self.temporal_encoder(spatial_feats) return temporal_feats
class PoseGuidedPretraining(nn.Module): """ Stage 1: 姿态引导预训练 训练时用 3D 姿态作为监督 推理时移除姿态头,仅用雷达 论文 Section 3.2 """ def __init__(self, hidden=256, pose_dim=66): super().__init__() self.encoder = SpatioTemporalRadarEncoder() self.pose_head = nn.Sequential( nn.Linear(hidden, hidden), nn.GELU(), nn.Linear(hidden, pose_dim) ) def forward(self, radar_sequence, return_pose=False): features = self.encoder(radar_sequence) if return_pose: pose_pred = self.pose_head(features) return features, pose_pred else: return features
class mmMindModel(nn.Module): """ mmMind: 完整的雷达-语言模型 论文:arXiv:2608.04127 """ def __init__(self, hidden=256, llm_dim=4096, num_radar_tokens=32): super().__init__() self.radar_encoder = PoseGuidedPretraining(hidden=hidden) for param in self.radar_encoder.parameters(): param.requires_grad = False self.projection = nn.Sequential( nn.Linear(hidden, llm_dim), nn.GELU(), nn.Linear(llm_dim, llm_dim) ) self.query_tokens = nn.Parameter( torch.randn(num_radar_tokens, llm_dim) ) self.llm_dim = llm_dim def forward(self, radar_sequence, text_input=None): """ Args: radar_sequence: (B, T, C, D_r, D_d, D_a) text_input: 文本输入(问答模式) Returns: radar_tokens: (B, num_tokens, llm_dim) - 用于 LLM """ features = self.radar_encoder(radar_sequence) projected = self.projection(features) B = projected.shape[0] queries = self.query_tokens.unsqueeze(0).expand(B, -1, -1) radar_tokens = torch.cat([queries, projected], dim=1) return radar_tokens
|