系列 · PDE × 机器学习 · 第 1 篇

偏微分方程与机器学习(一):物理信息神经网络

从有限差分到 PINN:自动微分、PDE 残差损失、Neural Tangent Kernel 视角的训练病理、Burgers 反问题、与 FEM/神经算子的对比,配 7 张实验图。

本系列第一章 · 阅读约 35 分钟。 这章是整个系列的地基。后面七章讲神经算子、变分原理和 Score Matching,其实都在探讨同一个问题:如何将物理或数学约束编码进神经网络的优化目标?搞定了 PINN,后续章节只是更换不同的约束。

偏微分方程与机器学习(一):物理信息神经网络 — 章节概览图


第一章 · 阅读约 35 分钟。 这是整个系列的地基。后面七章讲神经算子、变分原理、score matching,本质上都在做同一件事——把物理或数学约束直接编码进神经网络的优化目标。把 PINN 弄明白了,后面只是换约束。

如果你读这篇文章时心里只有一个问题,建议是这个:“神经网络怎么知道一个 PDE 是什么?” 答案出乎意料的简单——不让它自己猜,而是把 PDE 残差直接写成损失函数的一部分。一旦这一步想通,下面所有技术细节(自动微分、损失加权、训练病理)都只是把这个想法做工整。

引子:从一根金属棒说起#

预测金属棒温度 $u(x,t)$ ,过去半个世纪有两个标准方法:

  1. 有限差分(FDM):把 $[0,L]$ 分成 $N$ 段,$[0,T]$ 分成 $M$ 段,二阶导用三点差分代替,递推求解。
  2. 有限元(FEM):将区域进行三角剖分,在三角形内用线性多项式近似,使弱形式残差与测试函数正交。

两种方法都很成熟,但痛点相同——先建网格。一维棒还好,机翼形状就麻烦,十维相空间直接死于“维度灾难”:网格点数 $\propto h^{-d}$$d=10$$h=0.1$ 就是 $10^{10}$ 个点。

2019 年 Raissi、Perdikaris 和 Karniadakis 在 Journal of Computational Physics 提出了第三条路 1

不要网格。用神经网络 $u_\theta(x,t)$ 直接逼近解,把“满足 PDE”写成损失函数。

这个想法可以追溯到 Lagaris (1998) 2,甚至 Ritz (1908) 的变分法——将“解 PDE”转化为“在函数空间中最小化泛函”。 Ritz 用分片多项式, PINN 用神经网络; PINN 的杀手锏是自动微分:高阶导用一行 torch.autograd.grad 算出,机器精度,没有截断误差。

PINN 架构:MLP + 自动微分 + 物理信息损失。
图 1: PINN 架构。输入 $(x,t)$ 进 MLP 输出 $\hat u$ ,自动微分提取 $\partial_t\hat u$$\partial_x^2\hat u$ ,组装 PDE 残差;与边界、初始/数据残差合为训练目标 $\mathcal L=\lambda_r\mathcal L_r+\lambda_b\mathcal L_b+\lambda_i\mathcal L_i$

本章顺序如下:§2 定量分析传统方法的痛点;§3 给出 PINN 的最小完备定义,并证明其与 Ritz–Galerkin 方法等价;§4 是核心部分,从 NTK 视角解释 PINN 难以训练的原因,并提出三种补救方案;§5 通过 Burgers 方程实验演示反问题;§6 列举失败模式与边界;§7 将 PINN 放在 SciML 地图上,与 FEM 和神经算子进行对比。

经典数值方法:看似成熟,实则有边界#

有限差分 —— 直觉的代价是稳定性#

有限差分法五点模板与有限元三角网格对比

$$u_t = \nu\, u_{xx},\qquad x\in(0,1),\ t>0,$$ $$\frac{u_i^{n+1}-u_i^n}{\tau}=\nu\frac{u_{i-1}^n-2u_i^n+u_{i+1}^n}{h^2}.$$

Von Neumann 分析给出稳定性条件 $\tau\le h^2/(2\nu)$ ——时间步长正比于 $h^2$ 。空间精度提高 10 倍,时间步需细 100 倍,总计算量涨 1000 倍。隐式 Crank–Nicolson 格式无条件稳定,但每步要解三对角线性方程组;高维依赖稀疏直接法或多重网格。

总结: FDM 的全局误差 $O(\tau+h^2)$ 由 Lax 等价定理保证。它在结构化网格上无敌,但无法处理复杂几何

有限元 —— 弱形式与变分原理#

$$ \underbrace{\int_\Omega \nabla u\cdot\nabla v\,\mathrm dx}_{a(u,v)} =\underbrace{\int_\Omega f v\,\mathrm dx}_{\ell(v)},\qquad \forall v\in H_0^1(\Omega). $$

这等价于最小化 Dirichlet 能量 $J(u)=\tfrac12 a(u,u)-\ell(u)$ 。在分片线性子空间 $V_h\subset H_0^1$ 中,设 $u_h=\sum c_j\phi_j$ ,求解 $Kc=f$ ,其中 $K_{ij}=a(\phi_i,\phi_j)$ 是稀疏正定刚度阵。

Céa 引理给出最优误差 $\|u-u_h\|_{H^1}\le C h^k\|u\|_{H^{k+1}}$FEM 的优势包括收敛性证明、误差控制和自适应网格细化,都是教科书内容。短板仍是网格——动边界、多孔介质、高维参数空间都难。

PINN 想破什么局#

结合 §2.1§2.2 ,传统方法共同的代价如下:

维度FDMFEM
网格必须,结构化必须,可非结构化
高阶导数离散星型,截断误差 $O(h^p)$弱化为一阶 + 测试函数
高维灾难灾难
复杂几何困难中等(生网格成本高)
反问题需另写优化外环同上
换边界 / 几何 / 参数全部重算全部重算

PINN 想一次解决最后三个痛点:无网格、高维友好、反问题与正问题统一优化。代价是没有传统收敛保证,靠新训练技巧弥补。

PINN 的最小完备定义#

数学陈述#

$$ \mathcal N[u](x,t) = 0,\quad (x,t)\in\Omega\times(0,T],\qquad \mathcal B[u]=g\ \text{on}\ \partial\Omega,\qquad u(x,0)=u_0(x). $$ $$ \boxed{\; \mathcal L(\theta) = \lambda_r\underbrace{\frac1{N_r}\sum_{i=1}^{N_r}|\mathcal N[u_\theta](x_i^r,t_i^r)|^2}_{\mathcal L_r:\,\text{PDE 残差}} +\lambda_b\underbrace{\frac1{N_b}\sum|\mathcal B[u_\theta]-g|^2}_{\mathcal L_b} +\lambda_i\underbrace{\frac1{N_i}\sum|u_\theta-u_0|^2}_{\mathcal L_i} +\lambda_d\underbrace{\frac1{N_d}\sum|u_\theta-u^{\mathrm{obs}}|^2}_{\mathcal L_d}\;} $$

$\mathcal L_d$ 在正问题中不存在,但在反问题中是核心。训练目标是 $\theta^\star=\arg\min_\theta \mathcal L(\theta)$ ,优化器用 Adam 或 L-BFGS。

三种损失项 + 加权策略对比。
图 2:左图——朴素等权重下, PDE 残差快速下降,边界损失停滞,解成了空气动力学家戏称的"physics-respecting noise";右图——NTK 自适应加权后,三条曲线同步下降,这才是健康收敛的表现。

完整的物理信息神经网络(PINN)实现:一维热传导方程#

在深入探讨自动微分(autodiff)为何关键之前,我们先从零开始构建一个完整的 PINN。考虑定义在区域 $[0,1] \times [0,1]$ 上的一维热传导方程:

$$\frac{\partial u}{\partial t} = \nu \frac{\partial^2 u}{\partial x^2}, \quad u(x,0) = \sin(\pi x), \quad u(0,t) = u(1,t) = 0$$

其精确解为 $u(x,t) = e^{-\nu \pi^2 t}\sin(\pi x)$ 。我们将仅利用该偏微分方程(PDE)、边界条件和初始条件来训练神经网络,无需任何网格划分——真正实现无网格(mesh-free)求解。

 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
import torch
import torch.nn as nn

nu = 0.01
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class PINN(nn.Module):
    def __init__(self, layers=[2, 64, 64, 64, 1]):
        super().__init__()
        nets = []
        for i in range(len(layers) - 1):
            nets.append(nn.Linear(layers[i], layers[i+1]))
            if i < len(layers) - 2:
                nets.append(nn.Tanh())  # 使用双曲正切作为隐藏层激活函数
        self.net = nn.Sequential(*nets)

    def forward(self, x, t):
        inp = torch.cat([x, t], dim=1)  # 将空间坐标 x 和时间 t 拼接为输入向量
        return self.net(inp)

model = PINN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

N_f = 10000
x_f = torch.rand(N_f, 1, requires_grad=True, device=device)
t_f = torch.rand(N_f, 1, requires_grad=True, device=device)

N_bc = 200
t_bc = torch.rand(N_bc, 1, device=device)      # 边界时间点(x=0 或 x=1 处)
x_ic = torch.rand(N_bc, 1, device=device)      # 初始空间点(t=0 处)

for epoch in range(5000):
    optimizer.zero_grad()

    # --- PDE 残差损失 ---
    u = model(x_f, t_f)
    u_t = torch.autograd.grad(u, t_f, torch.ones_like(u), create_graph=True)[0]
    u_x = torch.autograd.grad(u, x_f, torch.ones_like(u), create_graph=True)[0]
    u_xx = torch.autograd.grad(u_x, x_f, torch.ones_like(u_x), create_graph=True)[0]
    residual = u_t - nu * u_xx
    loss_pde = torch.mean(residual ** 2)

    # --- 边界损失:u(0,t) = u(1,t) = 0 ---
    x_left = torch.zeros(N_bc, 1, device=device)   # 左边界 x = 0
    x_right = torch.ones(N_bc, 1, device=device)    # 右边界 x = 1
    loss_bc = (torch.mean(model(x_left, t_bc)**2)
               + torch.mean(model(x_right, t_bc)**2))

    # --- 初始条件损失:u(x,0) = sin(πx) ---
    t_zero = torch.zeros(N_bc, 1, device=device)    # 初始时刻 t = 0
    u_ic_pred = model(x_ic, t_zero)
    u_ic_true = torch.sin(torch.pi * x_ic)          # 精确初始解
    loss_ic = torch.mean((u_ic_pred - u_ic_true)**2)

    # --- 总损失(加权组合)---
    loss = loss_pde + 10.0 * loss_bc + 10.0 * loss_ic
    loss.backward()
    optimizer.step()

    if epoch % 1000 == 0:
        print(f"Epoch {epoch}: PDE={loss_pde:.2e}, BC={loss_bc:.2e}, IC={loss_ic:.2e}")

这段代码中体现的关键设计选择包括:

  1. 三部分加权损失函数:总损失由 PDE 残差、边界条件和初始条件三部分加权构成。权重(此处对 BC/IC 均设为 10 倍)至关重要——第 3 节 将详细解释其影响机制。
  2. 自动微分(autodiff)驱动:我们从未显式离散化 $\partial u/\partial t$$\partial^2 u/\partial x^2$ ;而是完全依赖 PyTorch 的 autograd 机制,对网络输出关于输入 $(x,t)$ 进行精确、解析式的高阶求导
  3. 无网格随机采样:配置点直接在 $[0,1]^2$ 内均匀随机生成,不依赖任何网格结构、单元连接关系或有限元组装流程——真正释放了深度学习在连续建模中的表达潜力。

为什么自动微分重要#

$$\partial_x u \approx \frac{u(x+\varepsilon)-u(x-\varepsilon)}{2\varepsilon}$$

有两个致命问题:$\varepsilon$ 太小会被浮点误差淹没,高阶导数还会放大误差。反向自动微分(reverse-mode autodiff)是符号精确的:每个基本运算导数已知,链式法则自动组合,结果与解析导数一致到机器精度

1
2
3
4
5
6
7
def heat_residual(model, x, t, nu=0.1):
    x.requires_grad_(True); t.requires_grad_(True)
    u = model(torch.cat([x, t], dim=1))                # 前向传播
    u_t  = torch.autograd.grad(u, t, torch.ones_like(u), create_graph=True)[0]
    u_x  = torch.autograd.grad(u, x, torch.ones_like(u), create_graph=True)[0]
    u_xx = torch.autograd.grad(u_x, x, torch.ones_like(u_x), create_graph=True)[0]
    return u_t - nu * u_xx                             # 残差,期望 -> 0

create_graph=True 让导数留在计算图中,这样 loss = (residual**2).mean() 反传时能正确计算 $\nabla_\theta$

与 Ritz 方法的同构#

从抽象角度看:

  • Ritz:在子空间 $V_h=\mathrm{span}\{\phi_1,\dots,\phi_n\}$ 中最小化 $J(u)=\tfrac12 a(u,u)-\ell(u)$
  • PINN:在子空间 $V_\theta=\{u_\theta:\theta\in\mathbb R^p\}$ 中最小化 $\mathcal L(\theta)$

区别有两点:

  1. 基函数——分片多项式 vs 神经网络。后者非线性、光滑且频谱可调。
  2. 检验机制——Galerkin 用内积测试函数; PINN 用配点法 + Monte-Carlo 积分近似。

这样看, PINN 并不神秘,只是 “把 Ritz 的有限维子空间换成神经网络”。 Deep Ritz 3 显式化了这一点,直接最小化能量泛函而非残差平方,对椭圆型问题更稳定。

收敛性:有,但弱#

Shin–Darbon–Karniadakis (2020) 4 证明了线性二阶椭圆方程的渐近收敛性:当 $N_r\to\infty$ 、网络宽度 $\to\infty$$\mathcal L\to 0$ 时,$u_\theta\to u^\star$$L^2$ 意义下成立。但没有像 FEM 那样的定量收敛速率 $O(h^k)$ ——这是 PINN 和传统方法的最大差距。后续工作给出了一些 Sobolev 范数界,但工程级先验收敛阶仍遥不可及。

训练病理: PINN 真正难的地方#

偏微分方程与机器学习(一):物理信息神经网络 — 章节小结图

跑过 PINN 的人都知道,损失降到 0.01 后就不动了,边界条件也经常崩。下面讲三大病因和对应修补方法。

病因 A:损失项不平衡(梯度病理)#

Wang & Perdikaris (2021) 5 用梯度统计揭示了一个普遍现象:$\nabla_\theta\mathcal L_r$$\nabla_\theta\mathcal L_b$ 大几个数量级。 Adam 只会跟大梯度走,边界条件被淹没,网络“内部满足 PDE,但边界完全不对”。

梯度病理与谱偏差两大失败模式。
图 6 左:每层的 $\|\nabla_\theta\mathcal L_r\|$$\|\nabla_\theta\mathcal L_b\|$ 在对数尺度下差 3–4 个数量级——朴素 PINN 的典型分布。右:同一个网络逼近 $u=\sin(\pi x)+0.5\sin(8\pi x)+0.3\sin(20\pi x)$ ,低频几乎完美,高频几乎丢光,这是“谱偏差”。

$$ \hat\lambda_b = \frac{\max_\theta|\nabla_\theta\mathcal L_r|}{\overline{|\nabla_\theta\mathcal L_b|}},\qquad \lambda_b\leftarrow (1-\alpha)\lambda_b+\alpha\hat\lambda_b. $$

这是 Wang 的 learning-rate annealing 方法,几行代码就能让训不动的 PINN 收敛。

$$u_\theta(x,t) = x(1-x)\,\tilde u_\theta(x,t) + B(x,t),$$

$B$ 满足边界,$\tilde u_\theta$ 任意。这样 $\mathcal L_b\equiv 0$ ,不用平衡。

修补 3: NTK 平衡。 Wang–Yu–Perdikaris (2022) 6 证明 PINN 动力学由三个 Neural Tangent Kernel 主导,按 NTK 迹设权重最合理。

解决频谱偏差:傅里叶特征与 SIREN#

在深入剖析频谱偏差之前,我们先来看一种实用的解决方案。其核心思想是:如果标准多层感知机(MLP)难以表征高频函数,我们可以在将输入送入网络之前,将其映射到一个高频基空间中

随机傅里叶特征(RFF):将输入 $\mathbf{x}$ 映射为 $[\cos(B\mathbf{x}), \sin(B\mathbf{x})]$ ,其中 $B$ 是一个从 $\mathcal{N}(0, \sigma^2)$ 中采样的固定随机矩阵。带宽参数 $\sigma$ 控制所激发的频率范围。

 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
import torch
import torch.nn as nn
import numpy as np

class FourierFeatureLayer(nn.Module):
    # 用于缓解频谱偏差的随机傅里叶特征映射
    def __init__(self, in_dim, num_features=128, sigma=10.0):
        super().__init__()
        # B 不参与训练——它是固定的随机投影矩阵
        B = torch.randn(in_dim, num_features) * sigma
        self.register_buffer("B", B)

    def forward(self, x):
        proj = x @ self.B  # 形状: (batch, num_features)
        return torch.cat([torch.cos(proj), torch.sin(proj)], dim=-1)

class PINN_RFF(nn.Module):
    # 采用傅里叶特征编码输入的物理信息神经网络(PINN)
    def __init__(self, in_dim=2, num_features=128, sigma=10.0):
        super().__init__()
        self.rff = FourierFeatureLayer(in_dim, num_features, sigma)
        self.net = nn.Sequential(
            nn.Linear(2 * num_features, 128),
            nn.Tanh(),
            nn.Linear(128, 128),
            nn.Tanh(),
            nn.Linear(128, 128),
            nn.Tanh(),
            nn.Linear(128, 1),
        )

    def forward(self, x, t):
        inp = torch.cat([x, t], dim=1)
        features = self.rff(inp)
        return self.net(features)

SIREN(正弦表示网络):另一种方案,其每一层激活函数均采用正弦函数,并对频率参数进行精心初始化:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class SirenLayer(nn.Module):
    def __init__(self, in_features, out_features, omega_0=30.0, is_first=False):
        super().__init__()
        self.omega_0 = omega_0
        self.linear = nn.Linear(in_features, out_features)
        # 采用 Sitzmann 等人(2020)提出的特殊初始化方式
        with torch.no_grad():
            if is_first:
                self.linear.weight.uniform_(-1.0 / in_features, 1.0 / in_features)
            else:
                bound = np.sqrt(6.0 / in_features) / omega_0
                self.linear.weight.uniform_(-bound, bound)

    def forward(self, x):
        return torch.sin(self.omega_0 * self.linear(x))

如何选择?

方法参数建议适用场景
RFF$\sigma = 1$$10$适用于中等振荡程度的解;实现简单,仅需在输入层添加编码,无需改动网络主体结构。
RFF$\sigma > 10$激进式高频捕获;但若 $\sigma$ 过大,可能导致优化困难。
SIREN$\omega_0 = 30$特别适合解在多个尺度上均具有结构的问题(例如湍流、波干涉);需谨慎初始化,但能输出任意频率下光滑且无限可微的结果。

病因 B:谱偏差(spectral bias)#

NN 训练有明显规律:低频先学,高频后学(Rahaman 2019; Tancik 2020)。对 PINN 影响很大,因为 PDE 残差涉及二阶导,放大高频误差 $k^2$ 倍——网络越学不到高频,残差越大,恶性循环。

修补

  • Fourier 特征:把 $x$ 映到 $[\sin(2\pi B x),\cos(2\pi B x)]$$B$ 是高斯随机矩阵;这能拉平 NTK 频谱。
  • Sine 激活函数(SIREN):天然在频域分布能量,但初始化要小心。

病因 C:因果违背(causality)#

时间相关 PDE 满足“过去决定未来”。但 PINN 在 $\Omega\times[0,T]$ 上同时采点,相当于让网络一开始就拟合 $t=T$ ,如果 $t<T$ 错了,$t=T$ 也没意义。 Krishnapriyan 等 (2021) 7 把这叫 failure mode

$$w_n = \exp\bigl(-\varepsilon \sum_{k<n}\mathcal L_r(t_k)\bigr).$$

早期残差降下来后,晚期残差才加入总损失。

收敛对照实验#

把上述修补合在一起跑 Burgers 方程:

加 PDE 损失能否突破数据瓶颈。
图 4:仅 50 个含噪声标签时,纯监督训练(红)很快卡在 4% 误差;加入 PDE 残差后(蓝),物理约束把误差推到 0.3%。这是 PINN 区别于普通回归的核心价值。

方法对比:PINN vs 传统数值求解器 vs 神经算子#

在进入实验细节之前,我们先厘清物理信息神经网络(PINN)与其他主流方法的定位关系。下表总结了文献中积累的实践经验:

评判维度有限差分法(FDM)有限元法(FEM)物理信息神经网络(PINN)神经算子(FNO / DeepONet)
是否需要网格是(结构化网格)是(非结构化网格)否(推理阶段无需网格)
光滑偏微分方程的精度$O(h^2)$$O(h^4)$$O(h^{p+1})$$10^{-3}$$10^{-4}$$10^{-2}$$10^{-3}$
含奇异性或刚性问题的精度自适应网格细化(AMR)下表现优异自适应策略下表现优异若无特殊技巧,效果较差效果通常较差
训练/配置开销数分钟数分钟至数小时数小时至数天数小时(摊销至多次查询后)
单次推理耗时不适用(单次求解即完成)不适用(单次求解即完成)毫秒级毫秒级
维度扩展性遭遇维数灾难遭遇维数灾难表现稳健(无网格特性)表现稳健
反问题支持能力需手动实现伴随方程代码需手动实现伴随方程代码原生支持(直接将待估参数加入损失函数)需额外微调
适用场景建议低维问题、对精度要求极高且几何已知复杂几何、高精度需求高维问题、反问题、无法生成网格的情形多次查询场景(如设计优化、不确定性量化 UQ)

经验法则

  • 若你在 1D–3D 场景下需要 $10^{-6}$ 量级的精度,且几何结构明确,优先选用 FEM;
  • 若需对大量不同参数配置快速执行参数扫描(parametric sweep),神经算子是更优选择;
  • PINN 则在二者之间“大放异彩”:尤其适合反问题建模、高维偏微分方程求解,以及网格生成本身不可行(例如高维随机空间、不规则动态域)的场景。

基于残差的自适应重采样(RAR)#

一项关键技巧:在不增加总采样点数的前提下显著提升 PINN 精度——将配点集中布置在 PDE 残差较大的区域。这正是无网格框架下对传统自适应网格细化(AMR)思想的自然延伸。

 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
import torch

def adaptive_resample(model, x_domain, t_domain, N_total=10000, N_new=2000):
    # 在候选点集上评估残差
    N_cand = 50000
    x_cand = torch.rand(N_cand, 1, requires_grad=True, device=x_domain.device)
    t_cand = torch.rand(N_cand, 1, requires_grad=True, device=t_domain.device)

    with torch.no_grad():
        # 计算残差需梯度,此处临时解除 no_grad 模式(实际代码中需显式启用)
        pass

    # 在候选点处计算 PDE 残差
    x_cand.requires_grad_(True)
    t_cand.requires_grad_(True)
    u = model(x_cand, t_cand)
    u_t = torch.autograd.grad(u, t_cand, torch.ones_like(u), create_graph=True)[0]
    u_x = torch.autograd.grad(u, x_cand, torch.ones_like(u), create_graph=True)[0]
    u_xx = torch.autograd.grad(u_x, x_cand, torch.ones_like(u_x), create_graph=False)[0]

    residual = (u_t - 0.01 * u_xx).detach().abs().squeeze()

    # 选取残差最大的前 N_new 个点
    _, top_idx = torch.topk(residual, N_new)
    x_new = x_cand[top_idx].detach()
    t_new = t_cand[top_idx].detach()

    # 与均匀采样点混合,保障全域覆盖性
    N_uniform = N_total - N_new
    x_unif = torch.rand(N_uniform, 1, device=x_domain.device)
    t_unif = torch.rand(N_uniform, 1, device=t_domain.device)

    x_out = torch.cat([x_new, x_unif], dim=0).requires_grad_(True)
    t_out = torch.cat([t_new, t_unif], dim=0).requires_grad_(True)
    return x_out, t_out

对于具有局部强特征的问题(如激波、边界层),RAR 通常可在单轮迭代计算开销不变的前提下,将精度提升 3–10 倍。

实验: Burgers 方程与反问题#

正问题: Burgers 激波#

$$ u_t + u u_x = \nu u_{xx},\quad x\in[-1,1],\ t\in[0,1],\quad u(\pm 1,t)=0,\ u(x,0)=-\sin(\pi x),\ \nu=\tfrac{0.01}{\pi}. $$

参考解用 Cole–Hopf 变换 $u=-2\nu(\ln\phi)_x$ 把 Burgers 化为热方程,脚本 burgers_cole_hopf 就是干这个的。$\nu$ 很小,$t\approx 0.4$$x=0$ 附近形成接近间断的激波。

PINN 在 Burgers 方程上的预测 vs 精确解。
图 3:左侧色块图是 Cole–Hopf 参考解 $u(x,t)$ ,红蓝交界处是激波;右侧三幅是 $t=0.25/0.5/0.75$ 的切片, PINN (蓝色虚线)能捕捉激波位置和宽度——但仔细看, vanilla PINN 在激波两侧仍有约 5% 过冲, RAR、因果训练和 Sobolev 训练就是用来压这过冲的。

实战要点

  1. 网络 8 层 $\times$ 20 宽 tanh 激活函数够用,别盲目堆深度。
  2. 残差点 $N_r\sim 10^4$ ,用自适应残差细化(RAR):每隔几百步选 $|\mathcal N[u_\theta]|$ 最大的前 $k$ 个点加入训练集。
  3. Adam 优化器 1e-3 跑 20k 步打底,再切 L-BFGS 跑 5k 步精修。
  4. 归一化很重要:把 $(x,t)$ 映射到 $[-1,1]$ ,否则 NTK 会偏。

反问题:参数辨识#

正问题没啥稀奇,反问题才是 PINN 的亮点。加一项 $\mathcal L_d$ 拟合稀疏观测, PDE 中未知参数 $\nu$ 直接作为可训练标量参与梯度下降。

用稀疏含噪观测同时反演扩散系数。
图 5:左——只有 30 个时刻 $t=0.15$ 的含噪观测(红点);右——把 $\nu$ 当成可学习参数,与 $\theta$ 一起训练,$\nu$ 从初值 0.45 收敛到真值 0.10,偏差 < 1%。这种“正问题 + 反问题统一在单个损失函数里”的做法, FEM 几乎做不到。

PINN 反问题为啥省事:传统方法要嵌套两层优化——外层调参数,内层解 PDE 正问题;每次改参数都要重新跑一遍解算器。 PINN 把“满足 PDE”写进损失项,参数和 $\theta$ 共享梯度,省掉外环。代价是不确定性量化得靠 ensemble 或贝叶斯 PINN,不像传统 MCMC + FEM 那样有现成理论支持。

完整的反问题:恢复扩散系数#

物理信息神经网络(PINN)最具吸引力的应用之一是参数发现——即从稀疏且含噪声的观测数据中反演出偏微分方程(PDE)中未知的系数。本例中,我们仅利用 50 个带噪声的观测点,成功恢复热传导方程中的扩散系数 $\nu$

实验设定如下:我们在若干散点 $(x_i, t_i)$ 处观测到带噪声的解 $u(x_i, t_i) + \epsilon_i$ ,其中噪声项 $\epsilon_i \sim \mathcal{N}(0, 0.01^2)$ 。真实扩散系数 $\nu = 0.01$ 是未知的,被设为可训练参数。

 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
import torch
import torch.nn as nn

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

class InversePINN(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(2, 64), nn.Tanh(),
            nn.Linear(64, 64), nn.Tanh(),
            nn.Linear(64, 64), nn.Tanh(),
            nn.Linear(64, 1),
        )
        # 待学习的未知参数 —— 初始值设为一个错误猜测
        self.log_nu = nn.Parameter(torch.tensor([-2.0]))  # exp(-2) ≈ 0.135

    @property
    def nu(self):
        return torch.exp(self.log_nu)  # 强制保证 ν 为正数

    def forward(self, x, t):
        return self.net(torch.cat([x, t], dim=1))

nu_true = 0.01
N_obs = 50
x_obs = torch.rand(N_obs, 1, device=device)
t_obs = torch.rand(N_obs, 1, device=device) * 0.5  # 观测时间范围为 [0, 0.5]
u_obs = (torch.exp(-nu_true * torch.pi**2 * t_obs)
         * torch.sin(torch.pi * x_obs))
u_obs += 0.01 * torch.randn_like(u_obs)  # 添加高斯噪声

model = InversePINN().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

N_f = 5000

for epoch in range(10000):
    optimizer.zero_grad()

    # 每轮迭代重新采样配点,以提升空间覆盖均匀性
    x_f = torch.rand(N_f, 1, requires_grad=True, device=device)
    t_f = torch.rand(N_f, 1, requires_grad=True, device=device)

    # 使用当前学习到的 ν 计算 PDE 残差
    u = model(x_f, t_f)
    u_t = torch.autograd.grad(u, t_f, torch.ones_like(u), create_graph=True)[0]
    u_x = torch.autograd.grad(u, x_f, torch.ones_like(u), create_graph=True)[0]
    u_xx = torch.autograd.grad(u_x, x_f, torch.ones_like(u_x), create_graph=True)[0]
    residual = u_t - model.nu * u_xx
    loss_pde = torch.mean(residual ** 2)

    # 数据保真损失(拟合观测值)
    u_pred = model(x_obs, t_obs)
    loss_data = torch.mean((u_pred - u_obs) ** 2)

    # 边界条件损失(Dirichlet 零边界:u(0,t)=0, u(1,t)=0)
    N_bc = 100
    t_bc = torch.rand(N_bc, 1, device=device)
    loss_bc = (torch.mean(model(torch.zeros(N_bc, 1, device=device), t_bc)**2)
               + torch.mean(model(torch.ones(N_bc, 1, device=device), t_bc)**2))

    loss = loss_pde + 100.0 * loss_data + 10.0 * loss_bc
    loss.backward()
    optimizer.step()

    if epoch % 2000 == 0:
        print(f"第 {epoch} 轮:ν = {model.nu.item():.6f}(真实值 = 0.01),"
              f"数据损失 = {loss_data:.2e}")

print(f"恢复得到的 ν = {model.nu.item():.6f},相对误差 = "
      f"{abs(model.nu.item() - 0.01) / 0.01 * 100:.2f}%")

针对反问题的关键实现技巧:

  • 对数参数化(log_nu:我们优化的是 $\log \nu$ ,再通过指数映射还原为 $\nu$ 。这既确保了扩散系数恒为正,又在真实值极小时显著改善梯度传播效果。
  • 提高数据损失权重loss_data 的系数设为 100.0,迫使网络紧密贴合观测数据;若不加权,PDE 残差损失将主导训练过程,导致 $\nu$ 难以收敛。
  • 有限观测窗口,全域物理约束:我们仅在 $t \in [0, 0.5]$ 内有观测,但 PDE 残差在整个时空域上强制满足。此时 PDE 不再只是建模工具,更成为一种“物理驱动的正则器”,支撑模型向无数据区域合理外推。

失败模式与边界#

PINN 不是万能药。工业中常见问题如下:

失败模式原因现状
高频/多尺度(湍流)谱偏差 + 二阶导放大Fourier features、 cPINN 域分解缓解部分问题
接近间断(激波、相变)NN 偏好连续函数conservative PINN、 weak-form PINN 可用
长时间积分因果违背、误差累积因果训练、时间分块有效
病态条件(弱解非唯一)损失景观非凸添加先验、 ensemble 改善效果
复杂耦合(多物理)各项尺度差异大自适应权重、多任务学习应对
高维 ($d>10$ )残差采样维度灾难渐进采样、 Quasi-MC 提供思路

经验法则:几何复杂、高维、需参数反演 → PINN;精度要求高、几何规则、参数固定 → FEM/谱方法;多次查询同族 PDE → 神经算子。


PINN 在 SciML 地图上的位置#

PINN vs FEM vs 神经算子的能力雷达与代价/精度权衡。
图 7:左——六个维度评分(无网格、高维、复杂几何、单次速度、跨 PDE 泛化、精度保证);右——同个 PDE 不同方法的“求解时间 vs 误差”散点。 FEM 精度上限最高,但只适配特定几何; PINN 通用性强,单次求解贵;神经算子(DeepONet/FNO)训练后推理只需 ~1 秒,适合参数化 PDE,但训练数据来自 FEM 或 PINN。

选型口诀

  • FEM:经典方法,精度有保障,几何规则。工业仿真离不开它。
  • PINN:瑞士军刀,擅长反问题和先验融合类科研问题。
  • 神经算子(第 2 章:适合同族方程、不同输入函数、反复查询的场景,比如气象、半导体仿真、金融定价。

PINN 的定位不是取代 FEM,而是让先验物理成为深度学习模型设计的核心。这个主题贯穿后续章节。

与后续章节的衔接#

把 PINN 看作“约束嵌入损失函数”的一种形式,后面七章就清楚了:

读完本章,你应该能一句话概括:

PINN 是 mesh-free PDE 求解器,用神经网络作通用基函数,把 PDE 残差当损失函数,靠自动微分计算高阶导数到机器精度;瓶颈是训练动力学(NTK 分析揭示的梯度病理和谱偏差),不是表达能力。


✅ 检查点#

  1. 写出 PINN 损失函数三项的含义。
  2. 解释 NTK 尺度差异为何导致边界条件无法训练。
  3. 列出至少两种解决谱偏差的工程方法。
  4. 给定反问题,写出将未知参数加入计算图的代码框架。
  5. 何时选 PINN,何时选 FEM,何时选神经算子?

下一步#

本章给的几个核心想法(PDE 残差作为损失、函数空间上的算子、Wasserstein 几何、辛结构、score、扩散)在后面的章节里会反复出现。如果某一段卡住了,建议先记下问题继续往下读——下一章往往会从另一个角度把它再讲一遍。

如果你想验证自己读懂了,最直接的练习是把本章的方程在一个最小例子上跑通:一维热方程、单摆、二维高斯混合。代码不长,但能让公式从“看着对”变成“在我电脑上确实是对的”。

参考文献#



  1. M. Raissi, P. Perdikaris, G. E. Karniadakis. Physics-Informed Neural Networks: A Deep Learning Framework for Solving Forward and Inverse Problems Involving Nonlinear Partial Differential Equations. J. Comput. Phys., 378:686–707, 2019. doi:10.1016/j.jcp.2018.10.045  ↩︎

  2. I. E. Lagaris, A. Likas, D. I. Fotiadis. Artificial Neural Networks for Solving Ordinary and Partial Differential Equations. IEEE TNN, 9(5):987–1000, 1998. ↩︎

  3. W. E, B. Yu. The Deep Ritz Method. Commun. Math. Stat., 6(1):1–12, 2018. arXiv:1710.00211  ↩︎

  4. Y. Shin, J. Darbon, G. E. Karniadakis. On the Convergence of Physics-Informed Neural Networks for Linear Second-Order Elliptic and Parabolic Type PDEs. Commun. Comput. Phys., 28(5):2042–2074, 2020. arXiv:2004.01806  ↩︎

  5. S. Wang, Y. Teng, P. Perdikaris. Understanding and Mitigating Gradient Flow Pathologies in Physics-Informed Neural Networks. SIAM J. Sci. Comput., 43(5):A3055–A3081, 2021. arXiv:2001.04536  ↩︎

  6. S. Wang, X. Yu, P. Perdikaris. When and Why PINNs Fail to Train: A Neural Tangent Kernel Perspective. J. Comput. Phys., 449:110768, 2022. arXiv:2007.14527  ↩︎

  7. A. Krishnapriyan et al. Characterizing Possible Failure Modes in Physics-Informed Neural Networks. NeurIPS 2021. arXiv:2109.01050  ↩︎

本系列

PDE × 机器学习 8 篇

  1. 01 偏微分方程与机器学习(一):物理信息神经网络 当前
  2. 02 偏微分方程与机器学习(二):神经算子理论
  3. 03 偏微分方程与机器学习(三):变分原理与优化
  4. 04 偏微分方程与机器学习(四):变分推断与 Fokker-Planck 方程
  5. 05 偏微分方程与机器学习(五):辛几何与保结构网络
  6. 06 偏微分方程与机器学习(六):连续归一化流与 Neural ODE
  7. 07 偏微分方程与机器学习(七):扩散模型与 Score Matching
  8. 08 偏微分方程与机器学习(八):反应扩散系统与 GNN

读有所得?

GitHub 关注我 → 新文周更

GitHub