Download model/graphViT.py from OneScience-Group/EagleMeshTransformer: direct link, hf CLI and curl.
- Browser
- Download file 5.96 kB
-
https://huggingface.co/OneScience-Group/EagleMeshTransformer/resolve/main/model/graphViT.py
- Command line
-
hf download hf://OneScience-Group/EagleMeshTransformer/model/graphViT.py
-
curl -L -o graphViT.py https://huggingface.co/OneScience-Group/EagleMeshTransformer/resolve/main/model/graphViT.py
5.96 kB
| import torch | |
| import torch.nn as nn | |
| from onescience.modules.decoder.graphvit_decoder import GraphViTDecoder | |
| from onescience.modules.embedding.fourier_pos_embedding import FourierPosEmbedding | |
| from onescience.modules.encoder.graphvit_encoder import GraphViTEncoder | |
| from onescience.modules.pooling.rnn_cluster_pooling import RNNClusterPooling | |
| from onescience.modules.transformer.preln_transformer_block import ( | |
| PreLNTransformerBlock, | |
| ) | |
| # 节点类型常量 | |
| NODE_NORMAL = 0 | |
| NODE_INPUT = 4 | |
| NODE_OUTPUT = 5 | |
| NODE_WALL = 6 | |
| NODE_DISABLE = 2 | |
| class GraphViT(nn.Module): | |
| """ | |
| 该模型利用图神经网络提取局部特征,通过聚类池化在潜在空间进行全局 Transformer 交互, | |
| 最后解码回物理空间进行下一时刻的状态预测。 | |
| Args: | |
| state_size (int): 物理状态的维度(如速度 u, v, w)。 | |
| w_size (int): 潜在空间(Cluster Level)的特征维度。默认值: 512。 | |
| n_attention (int): Transformer 注意力层的数量。默认值: 4。 | |
| nb_gn (int): Encoder 中 GNN 的层数。默认值: 4。 | |
| n_heads (int): Transformer 注意力头数。默认值: 4。 | |
| """ | |
| def __init__(self, state_size, w_size=512, n_attention=4, nb_gn=4, n_heads=4): | |
| super(GraphViT, self).__init__() | |
| # 傅里叶位置编码参数 | |
| pos_start = -3 | |
| pos_length = 8 | |
| # 1. 编码器: Mesh Space -> Latent Graph | |
| self.encoder = GraphViTEncoder( | |
| nb_gn=nb_gn, | |
| state_size=state_size, | |
| pos_length=pos_length | |
| ) | |
| # 2. 池化层: Node Features -> Cluster Features | |
| self.graph_pooling = RNNClusterPooling( | |
| w_size=w_size, | |
| pos_length=pos_length | |
| ) | |
| # 3. 解码器: Cluster Features -> Node State Update | |
| self.graph_retrieve = GraphViTDecoder( | |
| w_size=w_size, | |
| pos_length=pos_length, | |
| state_size=state_size | |
| ) | |
| # 4. 潜在空间 Transformer 交互层 | |
| self.attention = nn.ModuleList([ | |
| PreLNTransformerBlock( | |
| w_size=w_size, | |
| pos_length=pos_length, | |
| n_heads=n_heads | |
| ) | |
| for _ in range(n_attention) | |
| ]) | |
| self.ln = nn.LayerNorm(w_size) | |
| self.noise_std = 0.0 | |
| # 5. 坐标嵌入层 | |
| self.positional_encoder = FourierPosEmbedding( | |
| pos_start=pos_start, | |
| pos_length=pos_length | |
| ) | |
| def forward( | |
| self, | |
| mesh_pos, | |
| edges, | |
| state, | |
| node_type, | |
| clusters, | |
| clusters_mask, | |
| apply_noise=False, | |
| ): | |
| """ | |
| 前向传播 (自回归滚动预测)。 | |
| 参数: | |
| mesh_pos: (B, T, N, 3) 节点坐标 | |
| edges: (B, T, M, 2) 边索引 | |
| state: (B, T, N, state_size) 节点物理状态 | |
| node_type: (B, T, N, 9) 节点类型 (One-hot) | |
| clusters: (B, T, K, C_max) 簇索引 | |
| clusters_mask: (B, T, K, C_max) 簇掩码 | |
| apply_noise: 是否在初始状态施加噪声 (Training 时通常为 True) | |
| """ | |
| if apply_noise: | |
| mask = torch.logical_or( | |
| node_type[:, 0, :, NODE_NORMAL] == 1, | |
| node_type[:, 0, :, NODE_OUTPUT] == 1, | |
| ) | |
| noise = torch.randn_like(state[:, 0]).to(state.device) * self.noise_std | |
| state[:, 0][mask] = state[:, 0][mask] + noise[mask] | |
| state_hat = [state[:, 0]] | |
| output_hat = [] | |
| target = [] | |
| # 从 t=1 开始预测,基于 t-1 的状态 | |
| for t in range(1, state.shape[1]): | |
| # 1. 生成位置编码 | |
| mesh_posenc, cluster_posenc = self.positional_encoder( | |
| mesh_pos[:, t - 1], clusters[:, t - 1], clusters_mask[:, t - 1] | |
| ) | |
| # 2. 图节点和边编码 | |
| V, E = self.encoder( | |
| mesh_pos[:, t - 1], | |
| edges[:, t - 1], | |
| state_hat[-1], | |
| node_type[:, t - 1], | |
| mesh_posenc, | |
| ) | |
| # 3. 聚类池化 | |
| W = self.graph_pooling( | |
| V, clusters[:, t - 1], mesh_posenc, clusters_mask[:, t - 1] | |
| ) | |
| # 4. 构建 Attention Mask | |
| attention_mask = clusters_mask[:, t - 1].sum(-1, keepdim=True) == 0 | |
| attention_mask = ( | |
| attention_mask.unsqueeze(1) | |
| .repeat(1, len(self.attention), 1, W.shape[1]) | |
| .view(-1, W.shape[1], W.shape[1]) | |
| ) | |
| attention_mask[:, torch.eye(W.shape[1], dtype=torch.bool)] = False | |
| attention_mask = attention_mask.transpose(-1, -2) | |
| # 5. 潜在空间 Transformer 交互 | |
| for a in self.attention: | |
| W = a(W, attention_mask, cluster_posenc) | |
| W = self.ln(W) | |
| # 6. 解码预测更新量 | |
| next_output = self.graph_retrieve( | |
| W, V, clusters[:, t - 1], mesh_posenc, edges[:, t - 1], E | |
| ) | |
| # 7. 更新下一时刻状态 | |
| next_state = state_hat[-1] + next_output | |
| target.append(state[:, t] - state_hat[-1]) | |
| # 8. 强制边界条件 (Mask 覆盖) | |
| mask = torch.logical_or( | |
| node_type[:, t, :, NODE_INPUT] == 1, node_type[:, t, :, NODE_WALL] == 1 | |
| ) | |
| mask = torch.logical_or(mask, node_type[:, t, :, NODE_DISABLE] == 1) | |
| next_state[mask, :] = state[:, t][mask, :] | |
| state_hat.append(next_state) | |
| output_hat.append(next_output) | |
| # 堆叠时间步 | |
| velocity_hat = torch.stack(state_hat, dim=1) | |
| output_hat = torch.stack(output_hat, dim=1) | |
| target = torch.stack(target, dim=1) | |
| # velocity_hat: [B, T, N, S], output_hat: [B, T-1, N, S] | |
| return velocity_hat, output_hat, target | |