PINN 与 HNN
数字脊髓(Spine 层)的核心挑战:如何在毫秒级实时控制中,既利用神经网络的非线性拟合能力,又保证物理定律的一致性?
纯数据驱动的黑盒神经网络有三个致命缺陷:OOD 物理幻觉、数据效率低、缺乏可证明的安全边界。EICPS 的答案是灰盒建模范式(Grey-box Modeling):
将物理先验(微分方程、守恒律)嵌入神经网络的损失函数结构,而非仅作为数据标签。
PINN:物理信息神经网络
架构流:输入 送入 NN 主干(128→128→n),预测状态导数 ;物理残差 从输出侧反馈回主干,构成约束闭环。配置点 无需对应实际观测数据——这是 PINN 与纯监督学习的根本区别。
损失函数:
在 EICPS 脊髓层的应用
对于机器人动力学 ,物理残差具体化为:
保证与局限
| 说明 | |
|---|---|
| ✅ OOD 不崩溃 | 物理方程约束兜底,远离训练分布时输出仍收敛到已知方程解 |
| ✅ 方程一致性 | 训练后满足 ,对应定律② |
| ❌ 不保证能量守恒 | 软约束(损失惩罚)无法阻止长时数值积分漂移 |
典型应用场景:湍流 / 摩擦建模、接触动力学、复杂非线性系统。
HNN:哈密顿神经网络
架构流:输入 (广义坐标 + 共轭动量)→ 网络(2n→128→1,输出标量哈密顿量)→ autograd 计算 → 乘辛矩阵 → 输出 。整条链中神经网络只学标量,辛结构由架构强制,而非损失惩罚。
哈密顿方程描述相空间辛流:
损失函数(仅需数据拟合,辛结构隐式保证):
保证与局限
| 说明 | |
|---|---|
| ✅ 能量守恒 | ,硬约束,对应定律① |
| ✅ Liouville 定理 | 相空间轨迹保持辛形式 不变 |
| ❌ 不建模耗散/外力 | 标准 HNN 仅适用保守系统;耗散场景需扩展为 Port-Hamiltonian |
典型应用场景:振荡 / 旋转运动、长时稳定性保证、能量健康监测。
灰盒协同:Spine Controller
PINN 遵循流形(切空间向量场)↔ HNN 守护能量(辛梯度向量场)——两者互补,共同构成 EICPS 脊髓层的灰盒控制器:
| PINN | HNN | |
|---|---|---|
| 约束类型 | 微分方程残差(软约束) | 辛结构守恒(硬约束) |
| 适用场景 | 湍流、摩擦、接触动力学 | 振荡、旋转、长时稳定性 |
| OOD 行为 | 收敛到已知方程解 | 轨迹保持辛流形上 |
| 定律关联 | 定律②方程一致性 + 定律③数据准确性 | 定律①守恒律优先 |
两者在 Spine Controller 合流,以 1kHz 实时运行:
PINN.predict_next(x, u) — 预测 ,Euler 积分得下一状态,学习切空间向量场,驱动参考轨迹生成。
HNN.check_energy(z) — 实时计算 、;若 ,立即触发安全反射弧,防止数值积分发散导致的机械失控。
物理 AI 三定律
EICPS 脊髓层的优先级从高到低:
| 优先级 | 定律 | 保证者 | 违反后果 |
|---|---|---|---|
| ① 最高 | 守恒律优先:(耗散)或 (保守) | HNN 架构强制 | 系统发散(电机过热、机械臂失控) |
| ② | 方程一致性: | PINN 训练保证 | 物理幻觉(OOD 区域产生不可行命令) |
| ③ 最低 | 数据准确性:最小化 | NN 拟合 | 仅模型精度下降,可数据增广改善 |
定律优先级决定了回退顺序:能量守恒失效时,无论轨迹多准确都必须触发停机;方程一致性失效时,即使数据拟合精度高也不可信任控制输出。
算法实现
import numpy as np
import torch
import torch.nn as nn
from torch.autograd import grad
# ── PINN:物理信息神经网络 ────────────────────────────────────
class PINNDynamicsModel(nn.Module):
"""
PINN 动力学模型:学习 ẋ = F(x, u) + physics_residual
物理残差约束保证 OOD 安全性
"""
def __init__(self, n_state: int, n_control: int, hidden: int = 128):
super().__init__()
self.n_state = n_state
self.n_control = n_control
# 神经网络主干:拟合未建模动力学
self.net = nn.Sequential(
nn.Linear(n_state + n_control, hidden),
nn.Tanh(),
nn.Linear(hidden, hidden),
nn.Tanh(),
nn.Linear(hidden, n_state),
)
# 已知物理先验(可选:惯量矩阵等)
self.M_inv = nn.Parameter(torch.eye(n_state // 2) * 0.1,
requires_grad=True)
def forward(self, x: torch.Tensor, u: torch.Tensor) -> torch.Tensor:
"""预测状态导数 ẋ"""
xu = torch.cat([x, u], dim=-1)
return self.net(xu)
def physics_residual(self, x: torch.Tensor, u: torch.Tensor,
x_dot_obs: torch.Tensor) -> torch.Tensor:
"""物理残差损失 L_phys:M(q)q̈ + C(q,q̇)q̇ + g(q) = τ"""
n = self.n_state // 2
ddq_pred = self.forward(x, u)[:, n:]
residual = (self.M_inv @ ddq_pred.T).T - u[:, :n]
return (residual ** 2).mean()
def total_loss(self, x: torch.Tensor, u: torch.Tensor,
x_dot_obs: torch.Tensor, lam: float = 1.0) -> torch.Tensor:
"""L_total = L_data + λ · L_phys"""
L_data = nn.functional.mse_loss(self.forward(x, u), x_dot_obs)
L_phys = self.physics_residual(x, u, x_dot_obs)
return L_data + lam * L_phys
# ── HNN:哈密顿神经网络 ───────────────────────────────────────
class HamiltonianNN(nn.Module):
"""
HNN:强制辛结构守恒
架构链:z=(q,p) → H_θ 网络 → autograd → ∇H → ×J → ż = J∇H
"""
def __init__(self, n_dof: int, hidden: int = 128):
super().__init__()
self.n = n_dof
# H(z): R^{2n} → R(标量哈密顿量)
self.H_net = nn.Sequential(
nn.Linear(2 * n_dof, hidden),
nn.Tanh(),
nn.Linear(hidden, hidden),
nn.Tanh(),
nn.Linear(hidden, 1),
)
def hamiltonian(self, z: torch.Tensor) -> torch.Tensor:
return self.H_net(z).squeeze(-1)
def forward(self, z: torch.Tensor) -> torch.Tensor:
"""辛梯度动力学:ż = J∇H(自动微分实现)"""
z = z.requires_grad_(True)
H_sum = self.hamiltonian(z).sum()
grad_H = grad(H_sum, z, create_graph=True)[0]
n = self.n
dq = grad_H[:, n:] # ∂H/∂p = q̇
dp = -grad_H[:, :n] # -∂H/∂q = ṗ
return torch.cat([dq, dp], dim=-1)
def energy_rate(self, z: torch.Tensor) -> torch.Tensor:
"""计算 dH/dt(用于健康监测,应趋近于零)"""
z_dot = self.forward(z)
z.requires_grad_(True)
H_sum = self.hamiltonian(z).sum()
grad_H = grad(H_sum, z, create_graph=True)[0]
return (grad_H * z_dot).sum(dim=-1)
# ── 灰盒脊髓控制器:PINN + HNN 合流 ─────────────────────────
class SpineController:
"""
EICPS 脊髓层:1kHz 实时灰盒控制器
PINN 预测下一状态;HNN 监测能量健康,超阈触发安全反射弧
"""
def __init__(self, pinn: PINNDynamicsModel, hnn: HamiltonianNN,
energy_warn: float = 0.1):
self.pinn = pinn
self.hnn = hnn
self.energy_warn = energy_warn
@torch.no_grad()
def predict_next(self, x: np.ndarray, u: np.ndarray,
dt: float = 0.001) -> np.ndarray:
"""PINN 单步预测(切空间向量场 → Euler 积分)"""
x_t = torch.tensor(x, dtype=torch.float32).unsqueeze(0)
u_t = torch.tensor(u, dtype=torch.float32).unsqueeze(0)
x_dot = self.pinn(x_t, u_t).squeeze(0).numpy()
return x + dt * x_dot
def check_energy(self, z: np.ndarray) -> dict:
"""HNN 能量健康监测:|dH/dt| > ε_warn → 触发安全反射弧"""
z_t = torch.tensor(z, dtype=torch.float32).unsqueeze(0)
H = self.hnn.hamiltonian(z_t).item()
dHdt = self.hnn.energy_rate(z_t).item()
safe = abs(dHdt) <= self.energy_warn
return {
"H": H,
"dH_dt": dHdt,
"safe": safe,
"action": "nominal" if safe else "safety_reflex",
}
延伸阅读
- 系统部署架构 — Spine 层在 EICPS 三层架构中的定位
- 接口协议 A/B — PINN/HNN 控制器的 1kHz 数据接口规范
- 跨频调度 — 物理流形的连续演化与离散跳变
- 实时安全监控(CBF) — HNN 能量异常触发安全反射弧的执行机制