Download model/PointNet.py from OneScience-Group/CFD_Benchmark: direct link, hf CLI and curl.
- Browser
- Download file 3.11 kB
-
https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/PointNet.py
- Command line
-
hf download hf://OneScience-Group/CFD_Benchmark/model/PointNet.py
-
curl -L -o PointNet.py https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/PointNet.py
3.11 kB
| import torch | |
| import torch.nn as nn | |
| import torch_geometric.nn as nng | |
| from onescience.modules.embedding import timestep_embedding, unified_pos_embedding | |
| from onescience.modules.mlp.MLP import StandardMLP | |
| class Model(nn.Module): | |
| """ | |
| PointNet 模型。 | |
| 用于处理点云数据,通过 MLP 提取局部特征,并使用全局最大池化提取全局特征。 | |
| """ | |
| def __init__(self, args, device): | |
| super(Model, self).__init__() | |
| self.__name__ = "PointNet" | |
| # 1. Input Block | |
| self.in_block = StandardMLP( | |
| input_dim=args.n_hidden, | |
| output_dim=args.n_hidden * 2, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 2. Max Pooling Block | |
| self.max_block = StandardMLP( | |
| input_dim=args.n_hidden * 2, | |
| output_dim=args.n_hidden * 32, | |
| hidden_dims=[args.n_hidden * 8], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 3. Output Block | |
| self.out_block = StandardMLP( | |
| input_dim=args.n_hidden * (2 + 32), # 34 * hidden | |
| output_dim=args.n_hidden * 4, | |
| hidden_dims=[args.n_hidden * 16], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 4. Encoder | |
| self.encoder = StandardMLP( | |
| input_dim=args.fun_dim + args.space_dim, | |
| output_dim=args.n_hidden, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 5. Decoder | |
| self.decoder = StandardMLP( | |
| input_dim=args.n_hidden, | |
| output_dim=args.out_dim, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| self.fcfinal = nn.Linear(args.n_hidden * 4, args.n_hidden) | |
| def forward(self, x, fx, T=None, geo=None): | |
| if geo is None: | |
| raise ValueError("Please provide edge index for Graph Neural Networks") | |
| # 兼容 batch_size = 1 输入 | |
| if x.dim() == 3: | |
| x = x.squeeze(0) # [1, N, C] → [N, C] | |
| if fx is not None and fx.dim() == 3: | |
| fx = fx.squeeze(0) | |
| assert ( | |
| x.size(0) > 0 # Simple check | |
| ), "Input cannot be empty" | |
| # 构造 batch 索引 | |
| batch = torch.zeros(x.shape[0], dtype=torch.long, device=x.device) | |
| # 编码 + 局部特征提取 | |
| z = torch.cat((x, fx), dim=-1).float() | |
| z = self.encoder(z) | |
| z = self.in_block(z) | |
| # 全局特征(max pooling) | |
| global_coef = self.max_block(z) | |
| global_coef = nng.global_max_pool(global_coef, batch=batch) | |
| # 重复 global coef 到每个点 | |
| nb_points = torch.tensor([batch.shape[0]], device=z.device) | |
| global_coef = global_coef.repeat_interleave(nb_points, dim=0) | |
| # 拼接全局 + 局部特征 | |
| z = torch.cat([z, global_coef], dim=1) | |
| z = self.out_block(z) | |
| z = self.fcfinal(z) | |
| z = self.decoder(z) | |
| return z.unsqueeze(0) | |