Download model/Graph_UNet.py from OneScience-Group/CFD_Benchmark: direct link, hf CLI and curl.
- Browser
- Download file 6.79 kB
-
https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/Graph_UNet.py
- Command line
-
hf download hf://OneScience-Group/CFD_Benchmark/model/Graph_UNet.py
-
curl -L -o Graph_UNet.py https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/Graph_UNet.py
6.79 kB
| import torch | |
| import torch.nn as nn | |
| import torch_geometric.nn as nng | |
| import random | |
| from onescience.modules.mlp.MLP import StandardMLP | |
| from onescience.modules.sample.SpatialGraphDownsample import SpatialGraphDownsample | |
| from onescience.modules.sample.SpatialGraphUpsample import SpatialGraphUpsample | |
| class Model(nn.Module): | |
| """ | |
| Graph U-Net 模型。 | |
| 基于图神经网络的 U-Net 结构,包含 Encoder-Decoder 和 Skip Connections。 | |
| 使用 SpatialGraphDownsample 进行图池化,使用 SpatialGraphUpsample 进行反池化。 | |
| """ | |
| def __init__( | |
| self, | |
| args, | |
| device, | |
| pool="random", | |
| scale=5, | |
| list_r=[0.05, 0.2, 0.5, 1, 10], | |
| pool_ratio=[0.5, 0.5, 0.5, 0.5, 0.5], | |
| max_neighbors=64, | |
| layer="SAGE", | |
| head=2, | |
| ): | |
| super(Model, self).__init__() | |
| self.__name__ = "Graph_UNet" | |
| # 参数绑定 | |
| self.L = scale | |
| self.layer = layer | |
| self.pool_type = pool | |
| self.pool_ratio = pool_ratio | |
| self.list_r = list_r | |
| self.size_hidden = args.n_hidden | |
| self.dim_enc = args.n_hidden | |
| self.bn_bool = True | |
| self.res = False | |
| self.head = head | |
| self.activation = nn.ReLU() | |
| self.encoder = StandardMLP( | |
| input_dim=args.fun_dim, | |
| output_dim=args.n_hidden, | |
| hidden_dims=[args.n_hidden * 2], | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| 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 | |
| ) | |
| # Down Path Layers | |
| self.down_convs = nn.ModuleList() | |
| self.down_samples = nn.ModuleList() | |
| self.down_bns = nn.ModuleList() | |
| # Level 0 (Initial) | |
| self._add_conv_layer(self.down_convs, self.dim_enc, self.size_hidden) | |
| if self.bn_bool: | |
| self._add_bn_layer(self.down_bns, self.size_hidden) | |
| # Level 1 to L-1 | |
| current_dim = self.size_hidden | |
| for n in range(self.L - 1): | |
| self.down_samples.append( | |
| SpatialGraphDownsample( | |
| in_channels=current_dim, | |
| ratio=self.pool_ratio[n], | |
| r=self.list_r[n], | |
| max_num_neighbors=max_neighbors, | |
| pool_method=self.pool_type | |
| ) | |
| ) | |
| # Conv Layer | |
| in_c = current_dim | |
| out_c = 2 * current_dim if layer == "SAGE" else current_dim | |
| self._add_conv_layer(self.down_convs, in_c, out_c) | |
| current_dim = out_c | |
| if self.bn_bool: | |
| self._add_bn_layer(self.down_bns, current_dim) | |
| # Up Path Layers | |
| self.up_convs = nn.ModuleList() | |
| # --- 3. Upsample Module --- | |
| self.up_sampler = SpatialGraphUpsample() | |
| self.up_bns = nn.ModuleList() | |
| curr_h_init = args.n_hidden | |
| # Up Layer 0 (Top Layer) | |
| if self.layer == "SAGE": | |
| self.up_convs.append(nng.SAGEConv(3 * curr_h_init, self.dim_enc)) | |
| curr_h_init = 2 * curr_h_init | |
| elif self.layer == "GAT": | |
| self.up_convs.append(nng.GATConv(2 * self.head * curr_h_init, self.dim_enc, heads=2, concat=False)) | |
| if self.bn_bool: | |
| self.up_bns.append(nng.BatchNorm(self.dim_enc, track_running_stats=False)) | |
| # Up Layer 1 to L-1 (Middle Layers) | |
| for n in range(1, self.L - 1): | |
| if self.layer == "SAGE": | |
| self.up_convs.append(nng.SAGEConv(3 * curr_h_init, curr_h_init)) | |
| bn_dim = curr_h_init | |
| curr_h_init = 2 * curr_h_init | |
| elif self.layer == "GAT": | |
| self.up_convs.append(nng.GATConv(2 * self.head * curr_h_init, curr_h_init, heads=2, concat=True)) | |
| bn_dim = curr_h_init * 2 # GAT concat=True | |
| if self.bn_bool: | |
| self.up_bns.append(nng.BatchNorm(bn_dim, track_running_stats=False)) | |
| def _add_conv_layer(self, module_list, in_c, out_c): | |
| if self.layer == "SAGE": | |
| module_list.append(nng.SAGEConv(in_c, out_c)) | |
| elif self.layer == "GAT": | |
| module_list.append(nng.GATConv(in_c, out_c, heads=self.head, concat=True, add_self_loops=False)) | |
| def _add_bn_layer(self, module_list, in_c): | |
| dim = in_c * self.head if self.layer == "GAT" else in_c | |
| module_list.append(nng.BatchNorm(dim, track_running_stats=False)) | |
| def forward(self, x, fx, T=None, geo=None): | |
| if geo is None: raise ValueError("Edge index required") | |
| if fx.dim() == 3: fx = fx.squeeze(0) | |
| if geo.dim() == 3: edge_index = geo.squeeze(0) | |
| else: edge_index = geo | |
| # Encoder | |
| z = self.encoder(fx) | |
| if self.res: z_res = z.clone() | |
| # Downsampling Path | |
| skip_connections = [] | |
| pos_history = [] | |
| edge_index_history = [edge_index.clone()] | |
| # Level 0 Conv | |
| z = self.down_convs[0](z, edge_index) | |
| if self.bn_bool: z = self.down_bns[0](z) | |
| z = self.activation(z) | |
| skip_connections.append(z.clone()) | |
| # Assuming x contains coords in first 2 columns as per original code logic | |
| current_pos = x[:, :2] | |
| pos_history.append(current_pos.clone()) | |
| # Levels 1 to L-1 | |
| for n in range(self.L - 1): | |
| z, current_pos, edge_index, _ = self.down_samples[n](z, current_pos, edge_index) | |
| pos_history.append(current_pos.clone()) | |
| edge_index_history.append(edge_index.clone()) | |
| z = self.down_convs[n+1](z, edge_index) | |
| if self.bn_bool: z = self.down_bns[n+1](z) | |
| z = self.activation(z) | |
| skip_connections.append(z.clone()) | |
| # Up Path | |
| for n in range(self.L - 1, 0, -1): | |
| layer_idx = n - 1 | |
| pos_low = pos_history[n] | |
| pos_high = pos_history[n-1] | |
| z_skip = skip_connections[n-1] | |
| target_edge_index = edge_index_history[n-1] | |
| z = self.up_sampler(z, pos_low, pos_high) | |
| z = torch.cat([z, z_skip], dim=1) | |
| z = self.up_convs[layer_idx](z, target_edge_index) | |
| if self.bn_bool: | |
| z = self.up_bns[layer_idx](z) | |
| if n != 1: | |
| z = self.activation(z) | |
| # Decoder | |
| if self.res: z = z + z_res | |
| z = self.decoder(z) | |
| return z.unsqueeze(0) | |