从纯数据驱动到物理信息驱动:工业时序预测中的 PINNs (物理信息神经网络)实现

PINNs改造的工业工程价值

本次将纯TCN模型升级为PINNs,本质上是工业AI从纯数据驱动到数据与物理双驱动的范式级升级,核心是将模型学习的“数据→结果的映射函数”转变为“数据+物理规律→合法解空间中的函数”,把模型可行解空间从无限压缩到物理允许范围;从工程视角来看,其现实价值体现在五方面:一是解决工业AI信任危机,让模型从“能拟合”升级为“敢上线”,实现从AI demo到工程系统组件的跨越,杜绝反常识预测,获得一线工程师认可;二是结构性解决工业场景数据稀缺、冷启动、新工况等常态痛点,用物理规律替代“无限数据”,数据教模型具体值、物理教模型变化趋势,大幅提升投入产出比;三是实现泛化能力跃迁,从“插值器”变成具备弱外推能力的模型,在无数据覆盖的极端工况下也能输出物理合理的预测结果,做到“不会乱说话”;四是实现模型从黑盒到半白盒的转变,损失函数本身具备可解释性,且可通过调节λ权重平衡数据精度与物理合理性,让模型成为可调的工程工具;五是做出了典型的工业AI取舍,放弃理论更优的二阶导数约束,选择工程可用的一阶导数约束,实现“80%物理正确+100%可运行”的工程最优,贴合热工系统平滑性、无突变的天然特性,形成工业可落地的PINNs-lite架构;后续可从通用平滑约束升级为领域专属物理约束、实现λ动态调度、仅对关键变量施加物理约束三个方向进一步优化,而本次改造的核心意义,正是将工业时序预测的“拟合问题”转变为“求满足物理约束的最优解问题”。

导言

在工业 AI 的演进中,我们正经历从单纯数据驱动 → 数据+物理双驱动的范式转变。本文记录了一次实际项目改造:将标准 TCN(时间卷积网络)升级为 PINNs(物理信息神经网络),用于热工系统的温度预测。


第一部分:背景与动机

传统方法的局限

纯数据驱动模型的问题:

  • ❌ 在数据稀缺场景失效(工业系统常见)
  • ❌ 预测可能违背物理常识(如温度突跳)
  • ❌ 对分布外数据泛化能力差
  • ❌ 黑盒预测,难以获得工程师信任
    例子:轴承剩余寿命预测中,标准神经网络可能预测出不满足单调递减特性的结果。

PINNs 的核心思想

既然工业系统遵循物理规律,为什么不把这些规律当作硬约束写进损失函数?

L=Ldata⏟数据拟合+λ⋅Lphysics⏟物理约束\mathcal{L} = \underbrace{\mathcal{L}_{data}}_{\text{数据拟合}} + \underbrace{\lambda \cdot \mathcal{L}_{physics}}_{\text{物理约束}}L=数据拟合 Ldata+物理约束 λLphysics

优势:

  • ✅ 确定性高:预测结果物理合理
  • ✅ 小样本鲁棒:物理公式起"骨架"作用
  • ✅ 可理解性:约束可被工程师验证
  • ✅ 泛化能力:在极端条件下更稳定

第二部分:技术实现

项目结构

tcn2/
├── tcn_model.py # TCN 架构(因果卷积 + 残差 + 注意力)
├── data_utils.py # 3 个工业数据集生成
├── trainer.py # ✨ 新增:PINNs 损失函数
├── main.py # ✨ 修改:命令行支持 PINNs

核心算法:一阶导数平滑性约束

为什么选择一阶而非二阶导数?

初版使用二阶导数(拉普拉斯算子):
Lphysics=∑i=1F∥∂2T^∂xi2∥2\mathcal{L}_{physics} = \sum_{i=1}^{F} \left\|\frac{\partial^2 \hat{T}}{\partial x_i^2}\right\|^2Lphysics=i=1F xi22T^ 2

但遇到问题:

  • 计算二阶导数需要嵌套的 autograd.grad() 调用
  • 计算图爆炸,显存占用 ↑ 8 倍,容易爆显存
  • 在目前GPU 上几乎不可用
    优化方案:一阶平滑性约束 ⭐

改用一阶导数的 L2 范数约束:
Lphysics=∥∂T^∂x∥22\mathcal{L}_{physics} = \left\|\frac{\partial \hat{T}}{\partial x}\right\|_2^2Lphysics= xT^ 22

物理意义保留:

  • 约束温度预测对输入特征的变化率应接近零
  • 强制预测在特征空间中光滑变化
  • 符合热传导的平衡特性(热平衡时 ∇T≈0\nabla T \approx 0T0

定量对比

指标 二阶导数 一阶导数
显存占用 ~8GB(爆显存) ~1-2GB ✓
前向耗时 200ms/batch 50ms/batch ✓
反向耗时 500ms/batch 150ms/batch ✓
物理约束 ★★★★★ ★★★★☆
实用性 不可用 可用

实现细节

1. 损失函数设计(trainer.py)
class PhysicsInformedMSE(nn.Module):
    def __init__(self, model, device, lambda_physics=0.1):
        super().__init__()
        self.model = model
        self.device = device
        self.lambda_physics = lambda_physics
        self.mse_loss = nn.MSELoss()

    def forward(self, x, pred, target):
        # 数据损失
        loss_data = self.mse_loss(pred, target)
        
        # 物理损失:计算梯度的平滑性
        grad_pred = torch.autograd.grad(
            outputs=pred.sum(),
            inputs=x,
            create_graph=True,      # 保留计算图用于 backward
            retain_graph=True,      # 防止计算图被释放
            allow_unused=True
        )[0]
        
        if grad_pred is None:
            return loss_data
        
        loss_physics = (grad_pred ** 2).mean()
        
        # 加权总损失
        return loss_data + self.lambda_physics * loss_physics

关键点:

  • create_graph=True:保留计算图以计算更高阶导数
  • retain_graph=True:防止 backward() 时计算图被释放
  • allow_unused=True:处理某些输入不参与计算的情况
2. 训练循环修改(trainer.py)
# 初始化损失函数
if cfg.get("loss_fn", "mse") == "pinns":
    loss_fn = PhysicsInformedMSE(
        model=model,
        device=device,
        lambda_physics=cfg.get("lambda_physics", 0.1)
    )
else:
    loss_fn = LOSSES[cfg.get("loss_fn", "mse")]()

# 训练时
for xb, yb in train_loader:
    xb, yb = xb.to(device), yb.to(device)
    
    # PINNs 需要追踪输入梯度
    if cfg.get("loss_fn", "mse") == "pinns":
        xb.requires_grad_(True)
    
    opt.zero_grad()
    out = model(xb)
    
    # 调用方式因损失函数类型而异
    if cfg.get("loss_fn", "mse") == "pinns":
        loss = loss_fn(xb, out, yb)  # 传入输入 xb
    else:
        loss = loss_fn(out, yb)
    
    loss.backward()
    opt.step()
  1. 命令行集成(main.py)

p.add_argument(“–loss”, default=“pinns”,
choices=[“mse”,“mae”,“huber”,“rul_weighted”,“pinns”])
p.add_argument(“–lambda_physics”, type=float, default=0.1,
help=“PINNs 物理约束权重”)

设计思想:

  • 默认使用 PINNs(–loss pinns)
  • 用户可覆盖为标准损失函数对比
  • λ 可调,支持超参数搜索

3. 命令行集成(main.py)
p.add_argument("--loss", default="pinns",
               choices=["mse","mae","huber","rul_weighted","pinns"])
p.add_argument("--lambda_physics", type=float, default=0.1,
               help="PINNs 物理约束权重")

设计思想

  • 默认使用 PINNs(--loss pinns
  • 用户可覆盖为标准损失函数对比
  • λ 可调,支持超参数搜索

第三部分:实验与验证

实验设置

数据集:3 个工业场景

  1. bearing_rul:轴承剩余寿命预测(7 特征,2000 时间步)
  2. reactor_temp:化工反应釜温度预测(6 特征)
  3. steel_thickness:热轧钢板厚度偏差(6 特征)

模型:TCN-Attn(带注意力的时间卷积网络)

  • 感受野:19 时间步
  • 参数数量:~126K
  • 批大小:128(或 64 如果显存紧张)

结果

{
  "dataset": "bearing_rul",
  "loss_fn": "pinns",
  "lambda_physics": 0.1,
  "best_epoch": 111,
  "test_metrics": {
    "MSE": 0.0021185462828725576,
    "MAE": 0.024130484089255333,
    "RMSE": 0.04602766866649404,
    "R2": 0.9760236572573838,
    "SMAPE": 12.280920147895813
  }
}

在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐