简介
自 2019 年 PINNs 论文发表以来,研究者们提出了众多改进变体来解决原始 PINNs 的局限性。本文介绍几种重要的 PINNs 变体及其应用场景。
1. hp-VPINNs:变分物理信息神经网络
1.1 动机
原始 PINNs 使用 PDE 的强形式 (strong form),需要计算高阶导数。而 hp-VPINNs 采用弱形式 (weak form),通过变分原理减少导数阶数。
1.2 数学原理
对于椭圆型 PDE:
− ∇ ⋅ ( k ∇ u ) = f in Ω -\nabla \cdot (k \nabla u) = f \quad \text{in } \Omega
− ∇ ⋅ ( k ∇ u ) = f in Ω
强形式需要计算 ∇ 2 u \nabla^2 u ∇ 2 u 。而弱形式为:
∫ Ω k ∇ u ⋅ ∇ v d x = ∫ Ω f v d x , ∀ v ∈ V \int_\Omega k \nabla u \cdot \nabla v \, d\mathbf{x} = \int_\Omega f v \, d\mathbf{x}, \quad \forall v \in V
∫ Ω k ∇ u ⋅ ∇ v d x = ∫ Ω f v d x , ∀ v ∈ V
只需要一阶导数 ∇ u \nabla u ∇ u 。
1.3 hp 细化策略
h 细化 :增加计算域的子区域数量
p 细化 :在每个子区域内增加测试函数的多项式次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class VPINNLoss : """变分 PINN 损失函数""" def __init__ (self, test_functions ): self .test_functions = test_functions def compute (self, model, x, k, f ): u = model(x) u_x = torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u), create_graph=True )[0 ] loss = 0 for v in self .test_functions: v_x = torch.autograd.grad(v(x), x, grad_outputs=torch.ones_like(v(x)), create_graph=True )[0 ] lhs = torch.mean(k * u_x * v_x) rhs = torch.mean(f * v(x)) loss += (lhs - rhs) ** 2 return loss
1.4 优势
降低对网络光滑性的要求
更容易处理复杂边界条件
对非光滑解更鲁棒
2. XPINN:扩展物理信息神经网络
2.1 动机
原始 PINNs 难以处理大规模、复杂几何问题。XPINN 采用区域分解 策略,将计算域划分为多个子域。
2.2 方法
将 Ω \Omega Ω 分解为 K K K 个子域:
Ω = ⋃ k = 1 K Ω k , Γ i j = ∂ Ω i ∩ ∂ Ω j \Omega = \bigcup_{k=1}^K \Omega_k, \quad \Gamma_{ij} = \partial\Omega_i \cap \partial\Omega_j
Ω = k = 1 ⋃ K Ω k , Γ ij = ∂ Ω i ∩ ∂ Ω j
每个子域使用独立的神经网络 u k θ u_k^\theta u k θ 。
2.3 界面条件
在子域界面 Γ i j \Gamma_{ij} Γ ij 上施加连续性约束:
{ u i ( x ) = u j ( x ) , x ∈ Γ i j ∂ u i ∂ n i ( x ) = − ∂ u j ∂ n j ( x ) , x ∈ Γ i j \begin{cases}
u_i(\mathbf{x}) = u_j(\mathbf{x}), & \mathbf{x} \in \Gamma_{ij} \\
\frac{\partial u_i}{\partial n_i}(\mathbf{x}) = -\frac{\partial u_j}{\partial n_j}(\mathbf{x}), & \mathbf{x} \in \Gamma_{ij}
\end{cases}
{ u i ( x ) = u j ( x ) , ∂ n i ∂ u i ( x ) = − ∂ n j ∂ u j ( x ) , x ∈ Γ ij x ∈ Γ ij
2.4 损失函数
L = ∑ k = 1 K L k P D E + ∑ i < j ( L i j c o n t + L i j f l u x ) \mathcal{L} = \sum_{k=1}^K \mathcal{L}_k^{PDE} + \sum_{i<j} \left( \mathcal{L}_{ij}^{cont} + \mathcal{L}_{ij}^{flux} \right)
L = k = 1 ∑ K L k P D E + i < j ∑ ( L ij co n t + L ij f l ux )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class XPINN : """扩展物理信息神经网络""" def __init__ (self, n_subdomains ): self .networks = nn.ModuleList([ PINN([2 , 64 , 64 , 64 , 1 ]) for _ in range (n_subdomains) ]) def interface_loss (self, x_interface, i, j ): """界面连续性损失""" u_i = self .networks[i](x_interface) u_j = self .networks[j](x_interface) loss_cont = torch.mean((u_i - u_j) ** 2 ) return loss_cont
2.5 优势
并行化 :子域可并行训练
扩展性 :可处理更大规模问题
灵活性 :不同子域可使用不同网络架构
3. DeepONet:深度算子网络
3.1 动机
传统 PINNs 针对特定问题 训练,无法泛化。DeepONet 学习整个算子映射 ,可泛化到不同输入函数。
3.2 通用逼近定理
Chen & Chen (1995) 证明:任意连续算子 G G G 可以表示为:
G ( u ) ( y ) ≈ ∑ k = 1 p b k ( u ( x 1 ) , . . . , u ( x m ) ) ⏟ Branch Net ⋅ t k ( y ) ⏟ Trunk Net G(u)(y) \approx \sum_{k=1}^p \underbrace{b_k(u(x_1), ..., u(x_m))}_{\text{Branch Net}} \cdot \underbrace{t_k(y)}_{\text{Trunk Net}}
G ( u ) ( y ) ≈ k = 1 ∑ p Branch Net b k ( u ( x 1 ) , ... , u ( x m )) ⋅ Trunk Net t k ( y )
3.3 架构
DeepONet 包含两个子网络:
Branch Net :编码输入函数 u u u 在传感器点 { x i } \{x_i\} { x i } 处的值
Trunk Net :编码查询位置 y y y
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 class DeepONet (nn.Module): """深度算子网络""" def __init__ (self, branch_layers: list [int ], trunk_layers: list [int ], output_dim: int ): super ().__init__() self .branch_net = self ._build_mlp(branch_layers) self .trunk_net = self ._build_mlp(trunk_layers) self .output_dim = output_dim def _build_mlp (self, layers ): modules = [] for i in range (len (layers) - 1 ): modules.append(nn.Linear(layers[i], layers[i+1 ])) if i < len (layers) - 2 : modules.append(nn.Tanh()) return nn.Sequential(*modules) def forward (self, u_sensors: torch.Tensor, y: torch.Tensor ) -> torch.Tensor: """ Args: u_sensors: 输入函数在传感器点的值 y: 查询位置 Returns: G(u)(y): 算子在 y 处的输出 """ branch_out = self .branch_net(u_sensors) trunk_out = self .trunk_net(y) output = torch.sum (branch_out * trunk_out, dim=-1 , keepdim=True ) return output
3.4 训练
训练数据为多组 ( u , y , G ( u ) ( y ) ) (u, y, G(u)(y)) ( u , y , G ( u ) ( y )) 三元组:
1 2 3 4 5 6 7 8 9 10 11 12 def train_deeponet (model, data_loader, epochs=10000 ): optimizer = torch.optim.Adam(model.parameters(), lr=1e-3 ) for epoch in range (epochs): for u_sensors, y, target in data_loader: optimizer.zero_grad() pred = model(u_sensors, y) loss = F.mse_loss(pred, target) loss.backward() optimizer.step()
结合 PINNs 和 DeepONet:
L = L d a t a + λ p h y s i c s L p h y s i c s \mathcal{L} = \mathcal{L}_{data} + \lambda_{physics} \mathcal{L}_{physics}
L = L d a t a + λ p h ys i cs L p h ys i cs
其中 L p h y s i c s \mathcal{L}_{physics} L p h ys i cs 是 PDE 残差损失。
4. Fourier Neural Operator (FNO)
4.1 动机
DeepONet 在实践中有时受限于点评估。FNO 直接在傅里叶空间进行卷积,更适合周期性问题。
4.2 谱卷积
FNO 的核心是谱卷积层 :
( K ( ϕ ) v ) ( x ) = F − 1 ( R ϕ ⋅ F ( v ) ) ( x ) (\mathcal{K}(\phi)v)(x) = \mathcal{F}^{-1}\left( R_\phi \cdot \mathcal{F}(v) \right)(x)
( K ( ϕ ) v ) ( x ) = F − 1 ( R ϕ ⋅ F ( v ) ) ( x )
其中 F \mathcal{F} F 是傅里叶变换,R ϕ R_\phi R ϕ 是可学习的傅里叶空间权重。
4.3 PyTorch 实现
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 class SpectralConv2d (nn.Module): """2D 谱卷积层""" def __init__ (self, in_channels, out_channels, modes1, modes2 ): super ().__init__() self .in_channels = in_channels self .out_channels = out_channels self .modes1 = modes1 self .modes2 = modes2 scale = 1 / (in_channels * out_channels) self .weights1 = nn.Parameter( scale * torch.rand(in_channels, out_channels, modes1, modes2, 2 ) ) self .weights2 = nn.Parameter( scale * torch.rand(in_channels, out_channels, modes1, modes2, 2 ) ) def compl_mul2d (self, input , weights ): """复数乘法""" return torch.einsum("bixy,ioxy->boxy" , input , torch.view_as_complex(weights)) def forward (self, x ): batch_size = x.shape[0 ] x_ft = torch.fft.rfft2(x) out_ft = torch.zeros(batch_size, self .out_channels, x.size(-2 ), x.size(-1 )//2 + 1 , dtype=torch.cfloat, device=x.device) out_ft[:, :, :self .modes1, :self .modes2] = \ self .compl_mul2d(x_ft[:, :, :self .modes1, :self .modes2], self .weights1) out_ft[:, :, -self .modes1:, :self .modes2] = \ self .compl_mul2d(x_ft[:, :, -self .modes1:, :self .modes2], self .weights2) x = torch.fft.irfft2(out_ft, s=(x.size(-2 ), x.size(-1 ))) return x class FNO2d (nn.Module): """2D 傅里叶神经算子""" def __init__ (self, modes1, modes2, width ): super ().__init__() self .modes1 = modes1 self .modes2 = modes2 self .width = width self .fc0 = nn.Linear(3 , width) self .conv0 = SpectralConv2d(width, width, modes1, modes2) self .conv1 = SpectralConv2d(width, width, modes1, modes2) self .conv2 = SpectralConv2d(width, width, modes1, modes2) self .conv3 = SpectralConv2d(width, width, modes1, modes2) self .w0 = nn.Conv2d(width, width, 1 ) self .w1 = nn.Conv2d(width, width, 1 ) self .w2 = nn.Conv2d(width, width, 1 ) self .w3 = nn.Conv2d(width, width, 1 ) self .fc1 = nn.Linear(width, 128 ) self .fc2 = nn.Linear(128 , 1 ) def forward (self, x ): x = self .fc0(x) x = x.permute(0 , 3 , 1 , 2 ) x1 = self .conv0(x) x2 = self .w0(x) x = F.gelu(x1 + x2) x1 = self .conv1(x) x2 = self .w1(x) x = F.gelu(x1 + x2) x1 = self .conv2(x) x2 = self .w2(x) x = F.gelu(x1 + x2) x1 = self .conv3(x) x2 = self .w3(x) x = x1 + x2 x = x.permute(0 , 2 , 3 , 1 ) x = self .fc1(x) x = F.gelu(x) x = self .fc2(x) return x
4.4 应用场景
Darcy 流 :多孔介质流动
Navier-Stokes :湍流预测
气象预测 :全球天气建模
5. 其他变体
5.1 Conservative PINNs (cPINNs)
针对守恒律方程,强制满足守恒性质:
d d t ∫ Ω u d x = − ∮ ∂ Ω F ⋅ n d S \frac{d}{dt}\int_\Omega u \, dx = -\oint_{\partial\Omega} \mathbf{F} \cdot \mathbf{n} \, dS
d t d ∫ Ω u d x = − ∮ ∂ Ω F ⋅ n d S
5.2 Gradient-Enhanced PINNs
利用梯度信息增强训练:
L g r a d = ∑ i ∣ ∂ u θ ∂ x i − ∂ u d a t a ∂ x i ∣ 2 \mathcal{L}_{grad} = \sum_i \left| \frac{\partial u_\theta}{\partial x_i} - \frac{\partial u_{data}}{\partial x_i} \right|^2
L g r a d = i ∑ ∂ x i ∂ u θ − ∂ x i ∂ u d a t a 2
5.3 Hard-Constrained PINNs
通过网络架构硬编码 边界条件:
u θ ( x ) = B ( x ) + D ( x ) ⋅ N θ ( x ) u_\theta(x) = B(x) + D(x) \cdot N_\theta(x)
u θ ( x ) = B ( x ) + D ( x ) ⋅ N θ ( x )
其中 B ( x ) B(x) B ( x ) 满足边界条件,D ( x ) D(x) D ( x ) 在边界处为零。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class HardConstrainedPINN (nn.Module): """硬约束 PINN""" def __init__ (self, network ): super ().__init__() self .network = network def forward (self, x, t ): D = x * (1 - x) N = self .network(torch.cat([x, t], dim=1 )) u = D * N return u
5.4 Transfer Learning for PINNs
在相似问题间迁移学习:
在源问题上预训练
冻结前几层,微调后几层
适应目标问题
6. 工具与资源
6.1 开源框架
6.2 Benchmark 问题
热传导方程 :验证基本功能
Burgers 方程 :非线性对流
Allen-Cahn 方程 :相场模型
Navier-Stokes :流体力学
Schrödinger 方程 :量子力学
总结
PINNs 家族正在快速发展:
变体
核心改进
适用场景
hp-VPINNs
弱形式
非光滑解、复杂边界
XPINN
区域分解
大规模问题
DeepONet
算子学习
参数化问题族
FNO
谱方法
周期性、大规模
cPINNs
守恒性
守恒律方程
选择合适的变体取决于:
问题规模 :小问题用 PINNs,大问题用 XPINN/FNO
数据可用性 :少数据用 PINNs,有数据用 DeepONet
解的光滑性 :非光滑用 hp-VPINNs
泛化需求 :需泛化用 DeepONet/FNO
参考资料
Kharazmi, E., et al. (2021). hp-VPINNs: Variational physics-informed neural networks with domain decomposition. CMAME .
Jagtap, A. D., & Karniadakis, G. E. (2020). Extended physics-informed neural networks (XPINNs). CMAME .
Lu, L., et al. (2021). Learning nonlinear operators via DeepONet. Nature Machine Intelligence .
Li, Z., et al. (2021). Fourier neural operator for parametric partial differential equations. ICLR .