引言
物理信息神经网络(Physics-Informed Neural Networks, PINNs)是由 Raissi 等人于 2019 年提出的一种将物理定律嵌入神经网络训练过程的框架。1 传统数值方法(如有限元法、有限差分法)需要将连续问题离散化,而 PINNs 通过将偏微分方程(Partial Differential Equations, PDEs)的约束直接编码为神经网络的损失函数,利用自动微分(Automatic Differentiation, AD)技术实现对物理规律的端到端学习。
为什么需要 PINNs
传统 PDE 求解方法面临以下挑战:
| 方法 | 优点 | 缺点 |
|---|---|---|
| 有限元法(FEM) | 理论完善,精度高 | 网格生成复杂,高维问题维度灾难 |
| 有限差分法(FDM) | 实现简单 | 网格依赖,复杂几何形状处理困难 |
| 谱方法 | 高精度 | 仅适合规则区域,边界条件处理复杂 |
PINNs 的核心优势在于:
- 无网格方法:避免离散化,天然适合高维问题和复杂几何
- 数据驱动:可融合稀疏观测数据与物理约束
- 端到端学习:损失函数同时包含物理先验和数据拟合项
- 逆问题求解:可从少量观测数据中反推未知参数
核心思想
将 PDE 约束编码为损失函数
考虑一般形式的 PDE:
其中 是未知解, 是物理参数, 是微分算子。
PINNs 通过神经网络 近似解,并将 PDE 残差作为损失项:
自动微分求导
PINNs 利用自动微分技术精确计算神经网络的任意阶偏导数。给定网络 ,其导数可通过反向传播计算:
import torch
class PINN(torch.nn.Module):
def __init__(self, layers):
super().__init__()
self.fc = torch.nn.ModuleList([
torch.nn.Linear(layers[i], layers[i+1])
for i in range(len(layers)-1)
])
self.activation = torch.nn.Tanh()
def forward(self, x, t):
X = torch.cat([x, t], dim=1)
for i in range(len(self.fc)-1):
X = self.activation(self.fc[i](X))
return self.fc[-1](X)
def pde_residual(self, x, t, nu):
"""计算 Burgers 方程残差: u_t + u*u_x - nu*u_xx = 0"""
x.requires_grad_(True)
t.requires_grad_(True)
u = self.forward(x, t)
# 一阶导数
u_t = torch.autograd.grad(u, t, grad_outputs=torch.ones_like(u),
create_graph=True)[0]
u_x = torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u),
create_graph=True)[0]
# 二阶导数
u_xx = torch.autograd.grad(u_x, x, grad_outputs=torch.ones_like(u_x),
create_graph=True)[0]
# Burgers 方程残差
residual = u_t + u * u_x - nu * u_xx
return residual硬约束 vs 软约束
软约束(Soft Constraint):将边界条件和初始条件作为损失项加权加入:
硬约束(Hard Constraint):通过特殊网络架构强制满足边界条件:
- Bas sin 网络:将满足边界条件的解析基函数嵌入网络输出2
- 罚函数法:使用高权重强制边界条件
- 参数化变换:设计输出层结构使边界值自动为零
class HardConstraintPINN(torch.nn.Module):
"""硬约束示例:边界条件自动满足"""
def __init__(self, base_net):
super().__init__()
self.base_net = base_net
def forward(self, x, t):
"""
对区间 [0, 1] × [0, T],若边界条件为 u(0,t)=u(1,t)=0
使用 x*(1-x) 乘子自动满足
"""
u_base = self.base_net(x, t)
# x*(1-x) 确保 x=0 和 x=1 处为零
return x * (1 - x) * u_base损失函数设计
完整损失函数
PINNs 的总损失函数通常包含以下组成部分:
PDE 残差项
对于一般非线性 PDE:
常见 PDE 的残差形式:
| 方程 | 形式 | 残差 |
|---|---|---|
| Poisson | ||
| 热传导 | ||
| Burgers | ||
| Navier-Stokes | 见下方代码 |
def navier_stokes_residual(u_net, x, y, t, rho=1.0, nu=0.01):
"""2D 不可压 Navier-Stokes 方程"""
u = u_net(x, y, t)[:, 0:1] # u 速度
v = u_net(x, y, t)[:, 1:2] # v 速度
p = u_net(x, y, t)[:, 2:3] # 压力
# 开启梯度计算
u_x, u_y, u_t = compute_derivatives(u, [x, y, t])
v_x, v_y, v_t = compute_derivatives(v, [x, y, t])
_, _, p_x = compute_derivatives(p, [x, y, t])
_, _, p_y = compute_derivatives(p, [x, y, t])
u_xx = compute_2nd_derivative(u, x, x)
u_yy = compute_2nd_derivative(u, y, y)
v_xx = compute_2nd_derivative(v, x, x)
v_yy = compute_2nd_derivative(v, y, y)
# 连续性方程(不可压条件)
continuity = u_x + v_y
# 动量方程
momentum_x = u_t + u*u_x + v*u_y + p_x/rho - nu*(u_xx + u_yy)
momentum_y = v_t + u*v_x + v*v_y + p_y/rho - nu*(v_xx + v_yy)
return momentum_x, momentum_y, continuity边界条件(BC)项
Dirichlet 边界条件:
Neumann 边界条件:
周期性边界条件:
初始条件(IC)项
自适应权重策略
固定权重难以平衡不同损失项的梯度量级。自适应权重方法动态调整权重:
GradNorm 算法3:
其中 , 是平均梯度范数。
动态加权平均(DWA):
class AdaptiveWeightPINN:
def __init__(self, pinn, method='gradnorm', alpha=0.5):
self.pinn = pinn
self.method = method
self.alpha = alpha
self.weights = {'residual': 1.0, 'bc': 1.0, 'ic': 1.0, 'data': 1.0}
self.loss_history = {'residual': [], 'bc': [], 'ic': [], 'data': []}
def update_weights_gradnorm(self, losses, grads):
"""GradNorm 自适应权重更新"""
N = len(losses)
G_i = [torch.norm(g) for g in grads.values()]
G_avg = sum(G_i) / N
for key, G_i_val in zip(self.weights.keys(), G_i):
self.weights[key] = self.weights[key] * (G_avg / G_i_val) ** self.alpha
# 归一化
total = sum(self.weights.values())
for key in self.weights:
self.weights[key] /= total
def compute_weighted_loss(self, x, t, x_bc, t_bc, u_bc, x_ic, u_ic):
"""计算加权总损失"""
# 各分量损失
L_res = self.pinn.pde_residual(x, t)
L_bc = self.pinn.boundary_loss(x_bc, t_bc, u_bc)
L_ic = self.pinn.initial_loss(x_ic, u_ic)
# 返回加权损失和未加权损失(用于梯度计算)
weighted_loss = (self.weights['residual'] * L_res +
self.weights['bc'] * L_bc +
self.weights['ic'] * L_ic)
return weighted_loss, {'residual': L_res, 'bc': L_bc, 'ic': L_ic}网络架构
全连接网络(标准 PINNs)
标准 PINNs 使用多层全连接网络(Feedforward Neural Network, FNN):
其中 。
class StandardPINN(torch.nn.Module):
def __init__(self, input_dim, output_dim, hidden_layers=[64, 64, 64, 64],
activation='tanh'):
super().__init__()
activations = {
'tanh': torch.nn.Tanh(),
'relu': torch.nn.ReLU(),
'gelu': torch.nn.GELU(),
'sin': lambda x: torch.sin(x),
'siren': lambda x: torch.sin(30 * x)
}
act = activations.get(activation, torch.nn.Tanh())
layers = []
prev_dim = input_dim
for h_dim in hidden_layers:
layers.extend([
torch.nn.Linear(prev_dim, h_dim),
act
])
prev_dim = h_dim
layers.append(torch.nn.Linear(prev_dim, output_dim))
self.network = torch.nn.Sequential(*layers)
def forward(self, x, t):
return self.network(torch.cat([x, t], dim=1))残差连接(ResNet 型 PINNs)
深层网络训练困难,残差连接缓解梯度消失:
class ResidualBlock(torch.nn.Module):
def __init__(self, dim):
super().__init__()
self.fc1 = torch.nn.Linear(dim, dim)
self.fc2 = torch.nn.Linear(dim, dim)
self.activation = torch.nn.Tanh()
def forward(self, x):
residual = x
out = self.activation(self.fc1(x))
out = self.fc2(out)
return out + residual # 残差连接
class ResPINN(torch.nn.Module):
def __init__(self, input_dim, output_dim, hidden_dim=64, num_blocks=4):
super().__init__()
self.input_layer = torch.nn.Sequential(
torch.nn.Linear(input_dim, hidden_dim),
torch.nn.Tanh()
)
self.res_blocks = torch.nn.ModuleList([
ResidualBlock(hidden_dim) for _ in range(num_blocks)
])
self.output_layer = torch.nn.Linear(hidden_dim, output_dim)
def forward(self, x, t):
h = self.input_layer(torch.cat([x, t], dim=1))
for block in self.res_blocks:
h = block(h)
return self.output_layer(h)激活函数选择
| 激活函数 | 表达式 | 适用场景 |
|---|---|---|
| Tanh | 默认选择,光滑逼近 | |
| ReLU | 简单问题,计算高效 | |
| GELU | Transformer 风格架构 | |
| SIREN | 周期性/振荡问题 |
SIREN(正弦网络)4 对拉普拉斯算子具有归纳偏置:
class SIRENLayer(torch.nn.Module):
def __init__(self, in_dim, out_dim, omega=30):
super().__init__()
self.linear = torch.nn.Linear(in_dim, out_dim)
self.omega = omega
def forward(self, x):
return torch.sin(self.omega * self.linear(x))自适应采样策略
残差加权采样
高 PDE 残差区域需要更多采样点以降低逼近误差:
def residual_based_sampling(pinn, domain_bounds, N_samples, N_iterations=5):
"""
基于残差的自适应采样
1. 均匀采样计算残差
2. 按残差大小加权采样
3. 迭代细化
"""
x_min, x_max = domain_bounds['x']
t_min, t_max = domain_bounds['t']
all_points = []
for _ in range(N_iterations):
# 均匀采样
x = torch.rand(N_samples, 1) * (x_max - x_min) + x_min
t = torch.rand(N_samples, 1) * (t_max - t_min) + t_min
# 计算残差
residual = pinn.pde_residual(x, t)
residuals = torch.abs(residual).detach()
# 按残差加权采样(保留高残差点)
probs = residuals / residuals.sum()
indices = torch.multinomial(probs.view(-1), N_samples, replacement=True)
x_sampled = x[indices]
t_sampled = t[indices]
all_points.append((x_sampled, t_sampled))
return all_points分布平行采样(DPS)
DPS(Distribution Parallel Sampling)结合残差信息和边界层检测:
class DPSampler:
def __init__(self, domain, N_physics=1000, N_boundary=100, N_initial=100):
self.domain = domain
self.N_physics = N_physics
self.N_boundary = N_boundary
self.N_initial = N_initial
def sample(self, pinn, weights=None):
if weights is None:
weights = {'residual': 1.0, 'boundary': 1.0, 'initial': 1.0}
# 内部残差点
x_r, t_r = self.domain.sample_collocation(self.N_physics)
# 边界点(4个边界)
x_bc, t_bc, u_bc = self.domain.sample_boundary(self.N_boundary)
# 初始条件点
x_ic, t_ic, u_ic = self.domain.sample_initial(self.N_initial)
# 计算各区域残差并调整权重
if self.use_adaptive:
res_physics = pinn.pde_residual(x_r, t_r)
res_boundary = pinn.boundary_loss(x_bc, t_bc, u_bc)
res_initial = pinn.initial_loss(x_ic, u_ic)
# 调整采样分布
# ...
return {
'residual': (x_r, t_r),
'boundary': (x_bc, t_bc, u_bc),
'initial': (x_ic, t_ic, u_ic)
}动态权重调整
class DynamicSamplingPINN:
def __init__(self, pinn, domain, strategy='curriculum'):
self.pinn = pinn
self.domain = domain
self.strategy = strategy
self.residual_history = []
def compute_adaptive_loss(self, epoch, total_epochs):
# 学习率调度式采样:初期宽松,后期严格
if self.strategy == 'curriculum':
# 余弦退火式难度增加
progress = epoch / total_epochs
alpha = 0.5 * (1 + np.cos(np.pi * progress))
else:
alpha = 1.0
# 采样
x, t = self.domain.sample(self.N_points)
# 计算残差
residual = self.pinn.pde_residual(x, t)
# 残差加权损失
weights = torch.abs(residual) ** alpha
weighted_loss = (weights * residual ** 2).mean()
return weighted_loss挑战与局限
高维问题
PINNs 在高维问题()面临维度灾难:
- 均匀采样密度: 个点填满 维空间,每维仅有 个网格点
- 精度随维度指数衰减
解决方向:
- 神经算子(如 FNO、DeepONet)替代逐点逼近
- 稀疏数据驱动
- 低维流形假设
奇异性
PDE 解的奇异性(如裂缝、激波)导致网络难以精确拟合:
| 问题 | 表现 | 应对策略 |
|---|---|---|
| 导数奇异性 | 梯度爆炸,训练不稳定 | 软化奇异点、损失重加权 |
| 边界层 | 薄区域内梯度变化剧烈 | 网格加密、边界层检测 |
| 不连续解 | 连续网络无法精确表示 | 接触线检测、水平集方法 |
多尺度问题
物理系统常包含多个特征尺度:
当 时,出现边界层,PINNs 难以同时捕捉宏观和微观行为。
收敛性保证
PINNs 缺乏严格的收敛理论保证:
- 损失景观非凸,存在多个局部最优
- 自适应采样可能导致训练不稳定
- 梯度消失/爆炸问题
2025 年新进展
PINN 与神经算子结合
神经算子(Neural Operators)学习解算子映射 ,结合 PINNs 的物理约束:
Physics-Informed Neural Operator (PINO)5:
其中 是学习到的神经算子。
Physics-Informed Laplace Neural Operator (PI-LNO)6:
将拉普拉斯算子嵌入神经算子架构,利用傅里叶空间的谱特性提高计算效率。
收敛性理论进展
2024-2025 年理论工作取得重要进展:
- 过度参数化分析:证明足够宽的网络可收敛到 PDE 真解7
- 损失景观分析:揭示了物理约束项对优化动态的影响
- PAC-Bayes 框架:为 PINNs 提供泛化界
推理时间缩放
Physics-Informed Inference Time Scaling (PI-ITS)8 探索推理时计算资源与精度的关系:
- 训练阶段:标准 PINNs 训练
- 推理阶段:通过额外前向传播迭代精化预测
- 类似于 LLM 的推理时计算扩展范式
应用场景
流体力学
| 问题 | PDE | 典型应用 |
|---|---|---|
| Burgers 方程 | 交通流、激波建模 | |
| Navier-Stokes | 不可压/可压 NS 方程 | 翼型绕流、湍流模拟 |
| 浅水方程 | 波面方程 | 河流、海洋建模 |
# 2D Navier-Stokes 流体 PINN
class NavierStokesPINN(torch.nn.Module):
def __init__(self, nu=0.01, rho=1.0):
super().__init__()
self.net = StandardPINN(3, 3) # (x, y, t) -> (u, v, p)
self.nu = nu
self.rho = rho
def forward(self, x, y, t):
return self.net(x, y, t)
def loss(self, x, y, t, x_bc, y_bc, t_bc, u_bc, v_bc,
x_ic, y_ic, t_ic, u_ic, v_ic):
# PDE 残差
res_x, res_y, res_cont = navier_stokes_residual(self.net, x, y, t,
self.nu, self.rho)
L_pde = torch.mean(res_x**2 + res_y**2 + res_cont**2)
# 边界条件
u_pred, v_pred, _ = self.net(x_bc, y_bc, t_bc)
L_bc = torch.mean((u_pred - u_bc)**2 + (v_pred - v_bc)**2)
# 初始条件
u_ic_pred, v_ic_pred, _ = self.net(x_ic, y_ic, t_ic)
L_ic = torch.mean((u_ic_pred - u_ic)**2 + (v_ic_pred - v_ic)**2)
return L_pde + L_bc + L_ic热传导
热方程:
- 温度场预测
- 热传导反问题(从观测推断热导率 )
量子力学
薛定谔方程:
PINNs 可用于求解量子系统的基态和动力学演化。
生物医学
- 药物扩散建模
- 血流仿真
- 神经网络与生物物理模型结合
材料科学
- 相变建模
- 断裂力学
- 多物理场耦合
参考资料
Footnotes
-
Raissi, M., Perdikaris, P., & Karniadakis, G. E. (2019). Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations. Journal of Computational Physics, 378, 686-707. https://doi.org/10.1016/j.jcp.2018.10.045 ↩
-
Jagtap, A. D., Kawaguchi, K., & Karniadakis, G. E. (2020). Adaptive activation functions accelerate convergence in deep and physics-informed neural networks. Journal of Computational Physics, 404, 109136. https://doi.org/10.1016/j.jcp.2019.109136 ↩
-
Chen, Z., Liu, Y., & Sun, H. (2021). Physics-informed learning of governing equations from scarce data. Nature Communications, 12(1), 6136. https://doi.org/10.1038/s41467-021-26407-4 ↩
-
Sitzmann, V., Martel, J., Bergman, A., Lindell, D., & Wetzstein, G. (2020). Implicit neural representations with periodic activation functions. NeurIPS. https://proceedings.neurips.cc/paper/2020/hash/53c04118df206c0e8cc5dbd05942b0f4-Abstract.html ↩
-
Li, Z., Kovachki, N., Azizzadenesheli, K., et al. (2021). Physics-informed neural operator for learning partial differential equations. arXiv preprint. https://arxiv.org/abs/2111.03794 ↩
-
Physics-Informed Laplace Neural Operator (2025). arXiv:2602.12706. https://arxiv.org/abs/2602.12706 ↩
-
Shin, Y., Darbon, J., & Karniadakis, G. E. (2023). On the convergence of physics-informed neural networks for linear second-order elliptic and parabolic PDEs. Communications in Computational Physics. https://doi.org/10.4208/cicp.OA-2023-0289 ↩
-
Physics-Informed Inference Time Scaling (2025). arXiv:2504.16172. https://arxiv.org/abs/2504.16172 ↩