Download model/DeepONet.py from OneScience-Group/CFD_Benchmark: direct link, hf CLI and curl.
- Browser
- Download file 4.34 kB
-
https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/DeepONet.py
- Command line
-
hf download hf://OneScience-Group/CFD_Benchmark/model/DeepONet.py
-
curl -L -o DeepONet.py https://huggingface.co/OneScience-Group/CFD_Benchmark/resolve/main/model/DeepONet.py
4.34 kB
| import torch | |
| import torch.nn as nn | |
| from onescience.modules.mlp.MLP import StandardMLP | |
| from onescience.modules.embedding import timestep_embedding, unified_pos_embedding | |
| class Model(nn.Module): | |
| """ | |
| DeepONet 模型。 | |
| 采用双网络架构 (Branch Net 和 Trunk Net) 逼近非线性算子。 | |
| - Branch Net 处理输入函数 (如初始条件、边界条件)。 | |
| - Trunk Net 处理目标评估点的坐标 (物理位置)。 | |
| 两者输出特征做内积后得到目标位置的物理场预测值。 | |
| """ | |
| def __init__(self, args, device): | |
| super(Model, self).__init__() | |
| self.__name__ = "DeepONet" | |
| self.args = args | |
| # 位置处理 | |
| if args.unified_pos and args.geotype != "unstructured": | |
| self.pos = unified_pos_embedding(args.shapelist, args.ref, device=device) | |
| trunk_in_dim = args.ref ** len(args.shapelist) | |
| else: | |
| trunk_in_dim = args.space_dim | |
| # 分支网络输入维度(函数输入+时间嵌入) | |
| branch_in_dim = args.fun_dim | |
| if args.time_input: | |
| branch_in_dim += args.n_hidden # 增加时间嵌入维度 | |
| # 分支网络(函数空间) | |
| self.branch_net = StandardMLP( | |
| input_dim=branch_in_dim, | |
| output_dim=args.n_hidden, | |
| hidden_dims=[args.n_hidden] * args.branch_depth, | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 主干网络(物理空间) | |
| self.trunk_net = StandardMLP( | |
| input_dim=trunk_in_dim, | |
| output_dim=args.n_hidden, | |
| hidden_dims=[args.n_hidden] * args.trunk_depth, | |
| activation=args.act, | |
| use_bias=True | |
| ) | |
| # 时间处理层 | |
| if args.time_input: | |
| self.time_fc = nn.Sequential( | |
| nn.Linear(args.n_hidden, args.n_hidden), | |
| nn.SiLU(), | |
| nn.Linear(args.n_hidden, args.n_hidden), | |
| ) | |
| # 输出层 - 支持多个输出通道 | |
| self.out_layer = nn.Linear(args.n_hidden, args.out_dim) | |
| self.bias = nn.Parameter(torch.zeros(1, 1, args.out_dim)) | |
| def structured_forward(self, x, fx, T=None, geo=None): | |
| B, N, _ = x.shape # x: [B, N, space_dim] | |
| if self.args.unified_pos: | |
| x = self.pos.repeat(B, 1, 1) # [B, N, d] | |
| # 处理时间信息 | |
| if T is not None and self.args.time_input: | |
| # 确保时间输入维度正确 [B, 1] -> [B] | |
| T = T.view(-1) | |
| # 生成时间嵌入 [B, D] | |
| T_emb = timestep_embedding(T, self.args.n_hidden) | |
| # 通过时间处理层 [B, D] -> [B, D] | |
| T_emb = self.time_fc(T_emb) | |
| # 扩展时间嵌入以匹配空间点 [B, D] -> [B, N, D] | |
| T_emb_expanded = T_emb.unsqueeze(1).expand(-1, N, -1) | |
| # 将时间嵌入连接到函数输入 | |
| if fx is not None: | |
| # [B, N, fun_dim] + [B, N, D] = [B, N, fun_dim + D] | |
| fx = torch.cat([fx, T_emb_expanded], dim=-1) | |
| else: | |
| fx = T_emb_expanded # [B, N, D] | |
| # 分支网络处理 | |
| branch_feat = self.branch_net(fx) # [B, N, D] | |
| # 主干网络处理 | |
| trunk_feat = self.trunk_net(x) # [B, N, D] | |
| # 点积操作 + 输出层 | |
| inner = branch_feat * trunk_feat | |
| out = self.out_layer(inner) + self.bias | |
| return out | |
| def unstructured_forward(self, x, fx, T=None): | |
| B, N, _ = x.shape | |
| if T is not None and self.args.time_input: | |
| T = T.view(-1) | |
| T_emb = timestep_embedding(T, self.args.n_hidden) | |
| T_emb = self.time_fc(T_emb) | |
| T_emb_expanded = T_emb.unsqueeze(1).expand(-1, N, -1) | |
| if fx is not None: | |
| fx = torch.cat([fx, T_emb_expanded], dim=-1) | |
| else: | |
| fx = T_emb_expanded | |
| branch_feat = self.branch_net(fx) | |
| trunk_feat = self.trunk_net(x) | |
| inner = branch_feat * trunk_feat | |
| out = self.out_layer(inner) + self.bias | |
| return out | |
| def forward(self, x, fx, T=None, geo=None): | |
| if self.args.geotype == "unstructured": | |
| return self.unstructured_forward(x, fx, T) | |
| else: | |
| return self.structured_forward(x, fx, T) | |