深度学习基础:神经网络结构、损失函数、优化器与自动微分

物理信息神经网络(PINN)的核心思想是将物理方程(如Navier-Stokes方程、热传导方程)的残差作为损失项嵌入到神经网络训练中。因此,理解神经网络的基本构建模块——网络结构、损失函数、优化器以及自动微分——是搭建PINN模型的前提。本章将围绕这四个核心要素展开,重点说明它们在流体力学与热传导建模中的特殊考量与实现方式。

PINN 深度学习核心组件关系图 输入层 (x, y, z, t) 隐藏层(全连接) 权重 W, 偏置 b 激活函数 σ(·) 输出层 u, v, w, p, T 自动微分 ∂u/∂x, ∂²u/∂x² 链式法则 + 计算图 物理损失 (PDE残差) L_pde = ||N(u) - f||² 数据损失 L_data = ||u - u_obs||² L_total = L_pde + λ L_data 优化器 Adam / L-BFGS 梯度更新

上图展示了PINN中各组件的协作关系:输入坐标通过全连接网络前向传播得到预测场变量,自动微分从输出中计算各阶导数以构造PDE残差,数据损失与物理损失加权求和后,由优化器迭代更新网络参数。下面逐一深入剖析每个组件。

3.1 神经网络结构:全连接层与激活函数

在PINN中,最常用的网络结构是多层全连接前馈神经网络(MLP)。其数学表达为:

z^(0) = x
z^(l) = W^(l) · σ(z^(l-1)) + b^(l),  l = 1, 2, ..., L
u(x) = z^(L)

其中,W^(l) 和 b^(l) 分别是第 l 层的权重矩阵和偏置向量,σ(·) 是逐元素激活函数。对于流体力学问题,输入通常是时空坐标 (x, y, z, t),输出是速度分量 (u, v, w)、压力 p 和温度 T。

3.1.1 激活函数的选择策略

激活函数直接影响PINN的训练难度和精度。由于PDE残差需要计算高阶导数,激活函数的平滑性至关重要。常用选项对比如下:

激活函数表达式优点PINN中的问题
tanh(e^x - e^-x)/(e^x + e^-x)光滑、有界、二阶可导深层网络易梯度消失
sigmoid1/(1+e^-x)输出范围(0,1)梯度饱和严重,不推荐
ReLUmax(0, x)计算快、缓解梯度消失二阶导为0,无法用于PDE
Swishx · sigmoid(x)光滑、非单调计算量略大,效果较好
GELUx · Φ(x)光滑、近似ReLU适合复杂PDE

对于热传导方程(抛物型PDE)和Navier-Stokes方程,tanh 和 Swish 是首选。ReLU及其变体由于二阶导为零,无法构造扩散项 ∂²T/∂x²,应避免使用。

经验建议:对于包含压力场的不可压缩流动,建议在输出层对压力使用独立的缩放因子(如 p = p_scale * tanh(p_raw)),以匹配压力量级并加速收敛。

3.1.2 网络深度与宽度设计

PINN的近似能力取决于网络的容量。对于二维稳态热传导问题,4-6层隐藏层、每层50-100个神经元通常足够;而对于三维非稳态湍流,可能需要8-10层、每层100-200个神经元。但过深的网络会导致优化困难,建议配合残差连接(ResNet风格)或归一化技术。

3.2 损失函数:物理约束与数据拟合的加权融合

PINN的损失函数由三部分构成:

L_total = w_pde · L_pde + w_data · L_data + w_bc · L_bc

其中,L_pde 是PDE残差的均方误差,L_data 是观测数据拟合误差,L_bc 是边界/初始条件误差。权重 w 的选取对训练稳定性影响显著。

3.2.1 PDE残差的计算

以一维热传导方程 ∂T/∂t = α ∂²T/∂x² 为例,残差定义为:

r(x, t) = ∂T̂/∂t - α ∂²T̂/∂x²

其中 T̂ 是网络输出。训练时在计算域内随机采样 N_pde 个配点(collocation points),计算:

L_pde = (1/N_pde) Σ |r(x_i, t_i)|²

3.2.2 权重自适应策略

固定权重往往导致训练不平衡——PDE残差和边界损失量级差异大时,梯度被大项主导。常用解决方案包括:

  • 归一化损失:将各项损失除以初始值,使其量级一致。
  • 动态权重(NTK理论):根据梯度统计信息自动调整权重。
  • 学习率退火:先训练数据损失,再逐步引入PDE损失。
常见误区:不要将所有权重设为1。对于稳态Navier-Stokes方程,PDE残差通常比边界条件大2-3个数量级,若不调整权重,网络会忽略边界条件,导致解不唯一。

3.3 优化器:Adam与L-BFGS的协同使用

PINN训练通常采用两阶段策略:先用Adam进行全局搜索,再用L-BFGS进行局部精调。这是因为Adam对超参数不敏感、能快速逃离不良区域,但收敛精度有限;L-BFGS利用二阶信息,收敛快且精度高,但对初始点敏感。

3.3.1 Adam优化器

Adam(Adaptive Moment Estimation)结合动量与RMSProp,更新规则为:

m_t = β1 · m_{t-1} + (1-β1) · g_t
v_t = β2 · v_{t-1} + (1-β2) · g_t²
θ_{t+1} = θ_t - η · m̂_t / (√v̂_t + ε)

其中 g_t 是梯度,β1=0.9,β2=0.999,ε=1e-8。在PINN中,建议初始学习率 η=1e-3,并配合余弦退火或ReduceLROnPlateau策略。

3.3.2 L-BFGS优化器

L-BFGS(Limited-memory Broyden–Fletcher–Goldfarb–Shanno)是一种拟牛顿法,通过近似Hessian矩阵加速收敛。在PyTorch中,需使用 torch.optim.LBFGS,其特殊之处在于需要传入一个闭包函数来计算损失和梯度:

optimizer = torch.optim.LBFGS(model.parameters(), lr=1.0, max_iter=500)
def closure():
    optimizer.zero_grad()
    loss = compute_total_loss()
    loss.backward()
    return loss
optimizer.step(closure)
实战建议:先用Adam训练2000-5000步,观察损失下降曲线;当损失下降趋于平缓时,切换至L-BFGS继续训练至收敛。这种组合通常能将损失降低1-2个数量级。

3.4 自动微分:PINN的基石

自动微分(Automatic Differentiation, AD)是计算PDE残差中导数项的关键技术。与数值微分(有限差分)和符号微分不同,AD通过链式法则在计算图上精确计算导数,精度达到机器精度。

3.4.1 前向模式与反向模式

AD有两种模式:前向模式(forward mode)和反向模式(reverse mode)。PINN中,由于输出维度(速度、压力、温度)远小于输入维度(坐标+时间),通常使用反向模式(即反向传播),因为其计算复杂度与输出维度成正比,而非输入维度。

3.4.2 TensorFlow与PyTorch实现对比

框架高阶导数实现示例代码
TensorFlowtf.GradientTape 嵌套
with tf.GradientTape(persistent=True) as tape2:
    with tf.GradientTape() as tape1:
        u = model(x)
    du_dx = tape1.gradient(u, x)
d2u_dx2 = tape2.gradient(du_dx, x)
PyTorchtorch.autograd.grad 多次调用
u = model(x)
du_dx = torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u), create_graph=True)[0]
d2u_dx2 = torch.autograd.grad(du_dx, x, grad_outputs=torch.ones_like(du_dx), create_graph=True)[0]

在PyTorch中,create_graph=True 是必须的,否则无法计算二阶导数。TensorFlow中则需使用 persistent=True 以允许多次调用 gradient 方法。

3.4.3 计算图的内存管理

高阶导数会显著增加内存消耗。对于三维非稳态问题,二阶导数计算可能需要数GB显存。建议:

  • 使用 torch.no_grad() 包裹不需要梯度的计算(如验证集评估)。
  • 分批计算PDE残差,避免一次性计算所有配点的二阶导数。
  • 在TensorFlow中,使用 tf.function 编译计算图以提高效率。

3.5 案例拆解:二维稳态热传导PINN实现

考虑一个二维稳态热传导问题:在 [0,1]×[0,1] 方形域内,温度场满足拉普拉斯方程 ∂²T/∂x² + ∂²T/∂y² = 0,边界条件为:左侧 T=100,右侧 T=0,上下边界绝热(∂T/∂n=0)。

3.5.1 网络与损失设计

import torch
import torch.nn as nn

class PINN(nn.Module):
    def __init__(self):
        super().__init__()
        self.net = nn.Sequential(
            nn.Linear(2, 50), nn.Tanh(),
            nn.Linear(50, 50), nn.Tanh(),
            nn.Linear(50, 50), nn.Tanh(),
            nn.Linear(50, 1)
        )
    def forward(self, x, y):
        return self.net(torch.cat([x, y], dim=1))

# 损失计算
def pde_loss(model, x, y):
    x.requires_grad_(True)
    y.requires_grad_(True)
    T = model(x, y)
    dT_dx = torch.autograd.grad(T, x, grad_outputs=torch.ones_like(T), create_graph=True)[0]
    dT_dy = torch.autograd.grad(T, y, grad_outputs=torch.ones_like(T), create_graph=True)[0]
    d2T_dx2 = torch.autograd.grad(dT_dx, x, grad_outputs=torch.ones_like(dT_dx), create_graph=True)[0]
    d2T_dy2 = torch.autograd.grad(dT_dy, y, grad_outputs=torch.ones_like(dT_dy), create_graph=True)[0]
    return torch.mean((d2T_dx2 + d2T_dy2)**2)

3.5.2 训练过程与结果

在域内随机采样10000个配点,边界上各采样500个点。训练过程如下:

  1. Adam优化器,学习率 1e-3,训练3000步,损失从 1e2 降至 1e-3。
  2. 切换L-BFGS,最大迭代500次,损失降至 1e-6。
  3. 最终预测温度场与解析解(分离变量法)的最大误差 0.5%。
复盘要点:初始阶段PDE损失远大于边界损失,导致边界条件未被满足。通过将边界损失权重设为10,PDE损失权重设为1,训练速度提升约40%。此外,使用 tanh 激活函数比 Swish 收敛更快,但最终精度略低。

3.6 常见误区与总结

在PINN实践中,以下问题值得特别关注:

  • 激活函数选择不当:使用ReLU导致二阶导为零,PDE残差恒为零,网络无法学习。
  • 权重初始化不当:建议使用Xavier或He初始化,避免梯度爆炸或消失。
  • 配点采样不均匀:在边界附近应加密采样,否则边界层处的解精度差。
  • 忽略损失权重调整:固定权重往往导致训练失败,需根据损失量级动态调整。
  • 过早切换L-BFGS:若Adam尚未收敛到合理区域,L-BFGS可能陷入局部极小。