1. 案例1:物理约束神经网络求解一维稳态热传导
问题设定与物理约束
考虑一根长度 L = 1 m 的均质杆,导热系数 k = 1 W/(m·K),无内热源。稳态一维热传导方程为:
d²T/dx² = 0, x ∈ (0, L)
T(0) = T_left = 100 °C
T(L) = T_right = 0 °C
解析解为线性分布 T(x) = 100(1 - x)。本例用 PINN 学习该温度场,网络输入为坐标 x,输出为温度 T。训练损失由两部分加权组成:
- 物理残差损失
L_phys = mean( (d²T/dx²)² ),在内部配点上计算,约束方程成立; - 边界损失
L_bc = mean( (T(0)-100)² + (T(1)-0)² ),约束 Dirichlet 条件。
总损失 L = λ_phys·L_phys + λ_bc·L_bc。加权组合是关键:若 λ_phys 过大,边界约束被忽视,解整体漂移;若 λ_bc 过大,网络只拟合两端点而内部不满足方程。下面给出可运行的 PyTorch 实现。
关键实现:自动微分求二阶导
物理残差需要对网络输出关于输入求二阶导。PyTorch 中用 torch.autograd.grad 并设置 create_graph=True,使一阶导仍可继续求导。注意输入 x 必须 requires_grad=True。
import torch
import torch.nn as nn
torch.manual_seed(0)
class PINN(nn.Module):
def __init__(self, width=32):
super().__init__()
self.net = nn.Sequential(
nn.Linear(1, width), nn.Tanh(),
nn.Linear(width, width), nn.Tanh(),
nn.Linear(width, 1)
)
def forward(self, x):
return self.net(x)
def physics_residual(model, x):
x = x.clone().requires_grad_(True)
T = model(x)
dT = torch.autograd.grad(T, x, torch.ones_like(T), create_graph=True)[0]
d2T = torch.autograd.grad(dT, x, torch.ones_like(dT), create_graph=True)[0]
return d2T
model = PINN()
opt = torch.optim.Adam(model.parameters(), lr=1e-3)
# 内部配点与边界点
x_col = torch.rand(200, 1) # 内部配点
x_bc = torch.tensor([[0.0], [1.0]]) # 边界点
T_bc = torch.tensor([[100.0], [0.0]])
lam_phys, lam_bc = 1.0, 100.0 # 加权组合
for step in range(5000):
opt.zero_grad()
r = physics_residual(model, x_col)
loss_phys = (r ** 2).mean()
loss_bc = ((model(x_bc) - T_bc) ** 2).mean()
loss = lam_phys * loss_phys + lam_bc * loss_bc
loss.backward()
opt.step()
if step % 1000 == 0:
print(f"step {step:5d} L_phys={loss_phys.item():.3e} L_bc={loss_bc.item():.3e}")
加权组合的调参逻辑
边界损失量级通常远小于物理残差(残差是二阶导,数值小),因此 λ_bc 需要放大才能让边界条件被有效约束。经验做法:先固定 λ_phys=1,把 λ_bc 从 10 试到 1000,观察两项损失是否同步下降。若 L_bc 长期停在较大值,说明边界权重不足;若 L_phys 不降而 L_bc 迅速趋零,说明网络只记住了端点、内部方程未被满足。
验证预测误差
训练后在均匀网格上对比解析解,计算最大绝对误差与均方根误差:
x_test = torch.linspace(0, 1, 101).unsqueeze(1)
with torch.no_grad():
T_pred = model(x_test)
T_exact = 100.0 * (1 - x_test)
err = (T_pred - T_exact).abs()
print("最大绝对误差:", err.max().item())
print("RMSE:", torch.sqrt(((T_pred - T_exact) ** 2).mean()).item())
对线性解,合理训练后最大绝对误差通常可降到 1 °C 量级以下(示例预期,实际数值随随机种子与训练轮数变化)。若误差偏大,优先检查:配点是否覆盖整个区间、λ_bc 是否足够、训练轮数是否充分。
一维稳态问题的解析解是直线,可作为 PINN 流程的“最小可验证样例”:先确认损失下降、边界满足、误差收敛,再迁移到含非线性项或变系数的方程。