2025.2.23机器学习笔记:PINN文献阅读

2025.2.23周报

  • 一、文献阅读
    • 题目信息
    • 摘要
    • Abstract
    • 创新点
    • 网络架构
      • 架构A
      • 架构B
      • 架构C
    • 实验
    • 结论
    • 后续展望

一、文献阅读

题目信息

  • 题目: Physics-Informed Neural Networks for Modeling Water Flows in a River Channel
  • 期刊: IEEE TRANSACTIONS ON ARTIFICIAL INTELLIGENCE
  • 作者: Luis Fernando Nazari,Eduardo Camponogara,Laio Oriel Seman
  • 发表时间: 2024/03/03
  • 文章链接: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=9863669

摘要

洪水灾害对世界各地的影响重大,造成了严重的社会和经济问题,洪水防控策略依赖于水文预报模型,而这些模型主要通过数据驱动方法获得。所以模型需要达到期望的精度需要大量物理参数,而这些参数往往难以确获取;且传统的数据驱动模型往往需要可靠且真实的数据保证模型的数值模拟准确性。所以在以上背景研究下,本论文提出了一个基于物理信息神经网络(Physics-Informed Neural Networks,PINNs)的河道水流替代模型,作者总共设计了三个PINNs模型架构A、B、C,通过调节模型的输入与输出参数以探究在不同场景中模型的适用性。其中在架构C中作者引入了贝叶斯推断,限制参数偏离合理范围,提升物理可解释性。该论文旨在解决传统方法存在的问题,为流域水流的水文建模领域的研究做出贡献。

Abstract

Flood disasters exert profound impacts on populations worldwide, resulting in severe social and economic challenges. Effective flood prevention strategies hinge on hydrological forecasting models, which are predominantly derived through data-driven approaches. Achieving the desired precision in these models necessitates a multitude of physical parameters, which are often difficult to accurately acquire. Moreover, conventional data-driven models typically require reliable and authentic datasets to ensure the accuracy of numerical simulations. Against this backdrop, this paper proposes a surrogate model for river channel water flow based on Physics-Informed Neural Networks (PINNs). The authors developed three distinct PINN architectures—A, B, and C—by adjusting the input and output parameters to investigate their applicability across varying scenarios. Notably, in Architecture C, Bayesian inference is introduced to constrain parameter deviations within physically plausible ranges, thereby enhancing physical interpretability. This study aims to address the limitations inherent in traditional methodologies, contributing to advancements in the field of hydrological modeling for watershed water flows.

创新点

  1. 将PINNs应用于河道水流建模,通过融合圣维南方程的物理约束与实测数据,解决了传统方法中数据稀缺和参数依赖的问题;
  2. 通过PINNs直接预测水文动力学的关键参数,如:曼宁系数 n n n和河床坡度 S 0 S_0 S0。这种方法减少了传统方法中对地区数据的依赖;
  3. 使用了基于贝叶斯推理的PINNs训练新方法,解决参数预测的不确定性问题。

网络架构

本文提出了一种基于物理信息神经网络(PINN)的河流水流建模方法,重点解决了传统水文模型中参数识别困难和数据不足的问题。
作者提出了圣维南方程作为物理模型:
在这里插入图片描述
关于 Q ( x , t ) Q(x,t) Q(x,t) P w ( x , t ) P_w(x,t) Pw(x,t)的形象表示如下图所示:
在这里插入图片描述
下面对论文中三种网络架构进行分析:

架构A

  1. 输入
    ψ = [ x , t , h ( x , t ) , Δ h t ( x , t ) , Δ h x ( x , t ) ] ∈ R 5 \psi = [x, t, h(x,t), \Delta h_t(x,t), \Delta h_x(x,t)] \in \mathbb{R}^5 ψ=[x,t,h(x,t),Δht(x,t),Δhx(x,t)]R5
    其中,参数含义如下:
    x x x:空间;
    t t t:时间;
    h ( x , t ) h(x,t) h(x,t):水位;
    Δ h t \Delta h_t Δht
    数值微分计算的时间导数;
    Δ h x \Delta h_x Δhx:空间导数。
  2. 输出
    模型的输出为 Q Q Q水流速。
  3. 损失函数
    PINN的模型架构的损失函数由两部分组成:数据误差物理误差,即 Loss = MSE u + MSE p \text{Loss} = \text{MSE}_u + \text{MSE}_p Loss=MSEu+MSEp
    M S E u MSE_u MSEu为数据误差,公式表达为 MSE u = 1 N u ∑ i = 1 N u ∣ N N Q ( ψ u i ) − Q u i ∣ 2 \text{MSE}_u = \frac{1}{N_u} \sum_{i=1}^{N_u} \left| \mathcal{NN}_Q(\psi_u^i) - Q_u^i \right|^2 MSEu=Nu1i=1Nu NNQ(ψui)Qui 2,表示真实值与预测值之间的误差。具体展开为: MSE p = 1 N c ∑ i = 1 N c [ ∣ ∂ A ∂ t + ∂ N N Q ∂ x ∣ 2 + ∣ ∂ N N Q ∂ t + ∂ ∂ x ( N N Q 2 A ) + g A ( ∂ h ∂ x + S f − S 0 ) ∣ 2 ] \text{MSE}_p = \frac{1}{N_c} \sum_{i=1}^{N_c} \left[ \left| \frac{\partial A}{\partial t} + \frac{\partial \mathcal{NN}_Q}{\partial x} \right|^2 + \left| \frac{\partial \mathcal{NN}_Q}{\partial t} + \frac{\partial}{\partial x} \left( \frac{\mathcal{NN}_Q^2}{A} \right) + gA \left( \frac{\partial h}{\partial x} + S_f - S_0 \right) \right|^2 \right] MSEp=Nc1i=1Nc[ tA+xNNQ 2+ tNNQ+x(ANNQ2)+gA(xh+SfS0) 2]

在这里插入图片描述

架构B

  1. input
    ψ = [ x , t , h ( x , t ) ] ∈ R 3 \psi = [x, t, h(x,t)] \in \mathbb{R}^3 ψ=[x,t,h(x,t)]R3
    其中,参数含义如下:
    x x x:空间;
    t t t:时间;
    h ( x , t ) h(x,t) h(x,t):水位程高;
  2. output
    输出为: h和Q,分别表示水位高度与流速。
  3. Loss function
    损失函数扩展为三部分,分别为:数据误差圣维南方程质量守恒约束以及圣维南方程动量守恒约束
    l o s s f u n c t i o n = 1 N u ∑ i = 1 N u ∣ N N ( ψ u i ) − ( h i , Q i ) ∣ 2 + 1 N c ∑ i = 1 N c ∣ ∂ A ∂ h ∂ ∂ t N N h ( ψ c i ) + ∂ ∂ x N N Q ( ψ c i ) ∣ 2 + 1 N c ∑ i = 1 N c ∣ ∂ ∂ t N N Q ( ψ c i ) + ∂ ∂ x N N Q 2 ( ψ c i ) A ( x c i , t c i ) + g A ( x c i , t c i ) ( ∂ ∂ x N N h ( ψ c i ) + S f ( x c i , t c i ) − S 0 ) ∣ 2 loss function = \frac{1}{N_{u}} \sum_{i=1}^{N_{u}}\left|\mathcal{N N}\left(\psi_{u}^{i}\right)-\left(h^{i}, Q^{i}\right)\right|^{2} +\frac{1}{N_{c}} \sum_{i=1}^{N_{c}}\left|\frac{\partial A}{\partial h} \frac{\partial}{\partial t} \mathcal{N} \mathcal{N}_{h}\left(\psi_{c}^{i}\right)+\frac{\partial}{\partial x} \mathcal{N} \mathcal{N}_{Q}\left(\psi_{c}^{i}\right)\right|^{2} +\frac{1}{N_{c}} \sum_{i=1}^{N_{c}} \left\lvert\, \frac{\partial}{\partial t} \mathcal{N N}_{Q}\left(\psi_{c}^{i}\right)+\frac{\partial}{\partial x} \frac{\mathcal{N N}_{Q}^{2}\left(\psi_{c}^{i}\right)}{A\left(x_{c}^{i}, t_{c}^{i}\right)}\right. +\left.g A\left(x_{c}^{i}, t_{c}^{i}\right)\left(\frac{\partial}{\partial x} \mathcal{N} \mathcal{N}_{h}\left(\psi_{c}^{i}\right)+S_{f}\left(x_{c}^{i}, t_{c}^{i}\right)-S_{0}\right)\right|^{2} lossfunction=Nu1i=1Nu NN(ψui)(hi,Qi) 2+Nc1i=1Nc hAtNNh(ψci)+xNNQ(ψci) 2+Nc1i=1Nc tNNQ(ψci)+xA(xci,tci)NNQ2(ψci)+gA(xci,tci)(xNNh(ψci)+Sf(xci,tci)S0) 2
    其中, N c N_c Nc为配准点(collocation points)的数量,这些点是用来强制满足物理方程的时空坐标; N N h ( ψ c i ) \mathcal{N} \mathcal{N}_{h}\left(\psi_{c}^{i}\right) NNh(ψci):神经网络预测的水位高度h在配准点 ( x c i , t c i ) \left(x_c^i, t_c^i\right) (xci,tci)上的值; N N Q ( ψ c i ) \mathcal{N} \mathcal{N}_{Q}\left(\psi_{c}^{i}\right) NNQ(ψci):神经网络预测的水流量Q在配准 ( x c i , t c i ) \left(x_c^i, t_c^i\right) (xci,tci)上的值。
    在这里插入图片描述

架构C

  1. input
    ψ = [ x , t , h ( x , t ) , Δ h t ( x , t ) ] ∈ R 4 \psi = [x, t, h(x,t), \Delta h_t(x,t)] \in \mathbb{R}^4 ψ=[x,t,h(x,t),Δht(x,t)]R4
    其中,参数 R 4 \mathbb{R}^4 R4表示四维空间;
    x x x:空间;
    t t t:时间;
    h h h:水位;
    Δ h t \Delta h_t Δht:表示水面程高对时间t的求导。
  2. 输出
    输出与架构B相同都是 h h h Q Q Q,输出是一个二维向量。
  3. 损失函数
    与架构A和架构B不同的是,架构C在损失函数引入贝叶斯推断,增加惩罚项,其整体的损失函数表示为:
    Loss Function = 1 N u ∑ i = 1 N u ∣ N N ( ψ u i ) − [ h i , Q i ] ∣ 2 ⏟ 数据误差 + 1 N c ∑ i = 1 N c ∣ ∂ A ∂ h ∂ N N h ∂ t + ∂ N N Q ∂ x ∣ 2 ⏟ 质量守恒 + 1 N c ∑ i = 1 N c ∣ ∂ N N Q ∂ t + ∂ ∂ x N N Q 2 A + g A ( ∂ N N h ∂ x + S f − S 0 ) ∣ 2 ⏟ 动量守恒 + ∑ i = 1 N p 1 σ i 2 ( λ i − μ i ) 2 ⏟ 贝叶斯正则化 + 1 N c ∑ i = 1 N c ∣ ∂ N N h ∂ t − Δ h t ∣ 2 ⏟ 导数误差 \text{Loss Function} = \underbrace{\frac{1}{N_u} \sum_{i=1}^{N_u} \left| \mathcal{NN}(\psi_u^i) - [h^i, Q^i] \right|^2}_{\text{数据误差}} + \underbrace{\frac{1}{N_c} \sum_{i=1}^{N_c} \left| \frac{\partial A}{\partial h} \frac{\partial \mathcal{NN}_h}{\partial t} + \frac{\partial \mathcal{NN}_Q}{\partial x} \right|^2}_{\text{质量守恒}} + \underbrace{\frac{1}{N_c} \sum_{i=1}^{N_c} \left| \frac{\partial \mathcal{NN}_Q}{\partial t} + \frac{\partial}{\partial x} \frac{\mathcal{NN}_Q^2}{A} + g A \left( \frac{\partial \mathcal{NN}_h}{\partial x} + S_f - S_0 \right) \right|^2}_{\text{动量守恒}} + \underbrace{\sum_{i=1}^{N_p} \frac{1}{\sigma_i^2} \left( \lambda_i - \mu_i \right)^2}_{\text{贝叶斯正则化}} + \underbrace{\frac{1}{N_c} \sum_{i=1}^{N_c} \left| \frac{\partial \mathcal{NN}_h}{\partial t} - \Delta h_t \right|^2}_{\text{导数误差}} Loss Function=数据误差 Nu1i=1Nu NN(ψui)[hi,Qi] 2+质量守恒 Nc1i=1Nc hAtNNh+xNNQ 2+动量守恒 Nc1i=1Nc tNNQ+xANNQ2+gA(xNNh+SfS0) 2+贝叶斯正则化 i=1Npσi21(λiμi)2+导数误差 Nc1i=1Nc tNNhΔht 2
    引入贝叶斯推断可以参数 S 0 S_0 S0 n n n 更靠,贝叶斯推断表示为: 1 N p ∑ j = 1 N p 1 σ i 2 ( λ i − μ i ) 2 \frac{1}{N_p} \sum_{j=1}^{N_p} \frac{1}{\sigma_i^2} (\lambda_i - \mu_i)^2 Np1j=1Npσi21(λiμi)2
    其中, λ i \lambda_i λi为待估计参数; N p N_p Np为参数数量; μ i \mu_i μi参数的均值; σ i 2 {\sigma_i^2} σi2为参数的方差。
    在这里插入图片描述

架构A、B、C的比较以及适用场景

架构对输入参数的依赖车程度物理可解释性适用场景
A密集监测场景
B监测站稀疏的实际场景
C最高需平衡数据与物理定律的场景

实验

  1. PINNs用于河道水流建模的初步实验结果
    在模拟环境下,以圣维南方程配置构建的系统中进行实验,目的是在评估PINNs预测河道水流的有效性。实验分两个阶段,第一阶段假设PDE参数和水位函数已知,验证PINNs的数据同化能力;第二阶段聚焦于识别定义PDE的向量参数,以描述水流动力学并捕捉河道内在特征。
    通过数值解圣维南方程得到训练数据和配置点集,采用如架构A进行实验,结果表明PINN方法在系统识别方面,使用相对少的数据点,在所有实验中达到相当的精度和强大的数据同化能力,验证的均方误差在0.00648% - 0.0466%之间。
    在这里插入图片描述

  2. 不同架构下的建模结果
    架构A
    在将 S 0 S_0 S0 n n n作为优化变量加入损失函数后,经过一定训练轮次,架构A在所有实验中的预测误差(MSE)低于0.305%,最佳情况MSE为0.0263%。
    在这里插入图片描述
    基于PINNs发现的摩擦斜率和曼宁系数近似于圣维南方程中的实际参数,表明PINNs通过利用微分方程模型知识实现有效正则化。尽管没有理论保证神经网络模型和参数发现的联合学习收敛到全局最优,但在一定条件下可达到较好预测精度。
    在这里插入图片描述
    架构B
    为解决数据点缺乏问题提出架构B,其输入变量仅包含距离、时间和河流水位,输出除水流率外还尝试学习水位函数用于自动微分计算物理正则化中的偏导数。
    在这里插入图片描述
    实验结果显示架构B发现真实PDE参数的能力不如架构A,但能较好地近似系统行为,MSE验证指数较低。
    在这里插入图片描述
    架构C
    为改进参数识别提出架构C,采用新结构并受益于新的损失函数,引入贝叶斯推理到训练过程。
    架构C添加 Δ h t Δh_t Δht作为输入变量,新的损失函数包含对参数偏离均值的惩罚项和对输出自动微分与数值导数差异的惩罚项。
    实验结果表明,架构C在系统行为的泛化方面,MSE验证指数在0.0762% - 0.298%之间,相比架构B有所改进,在参数估计方面也有显著提升,能以较好的初始先验值逼近真实参数并保持物理特性。对比固定方差向量的情况,虽然参数有显著改进,但会导致系统识别能力的损失。
    在这里插入图片描述

  3. 伊塔雅伊米林河中的实验结果
    以伊塔雅伊河的伊塔雅伊米林河河段为研究对象,该区域有水位和流量测量数据,以及政府提供的地理研究数据。
    在这里插入图片描述
    利用2020年1月10 - 14日一次洪水事件的960个样本数据训练PINN模型,采用架构C并加入贝叶斯推理正则化的实验结果显示,架构为八层隐藏层、每层30个神经元、80000个配置点时,数据集同化效果最佳(MSE = 4.126×10⁻³),发现的床坡和曼宁系数参数,其中曼宁系数收敛到接近文献中的值,床坡参数收敛到区域研究中的极限值内。
    在这里插入图片描述
    在这里插入图片描述
    代码如下:

# 导入必要的库
import torch  # 用于张量计算和神经网络搭建
import torch.nn as nn  # 提供神经网络层和激活函数
import numpy as np  # 用于数据转换和绘图
import matplotlib.pyplot as plt  # 用于可视化训练结果
from time import time  # 用于测量训练时间
from pytorch_lbfgs import LBFGS  # 导入支持GPU的L-BFGS优化器# 设置随机种子,确保结果可重复
torch.manual_seed(42)# 检查并设置计算设备,确保使用GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
if not torch.cuda.is_available():raise RuntimeError("GPU not available. This code requires CUDA support.")
print(f"Using device: {device} ({torch.cuda.get_device_name(0)})")# 定义Saint-Venant方程
def saint_venant_equations(h, Q, x, t, S0, n, g=9.81, eps=1e-6):"""计算Saint-Venant方程的残差,用于物理约束"""width = 2.0  # 矩形横截面宽度2mA = h * width + eps  # 横截面积,添加偏移避免除零P_w = 2 * h + width + eps  # 湿周长,添加偏移R = A / P_w  # 水力半径# 自动微分计算偏导数h_t = torch.autograd.grad(h.sum(), t, create_graph=True)  # 计算 ∂h/∂th_t = h_t[0] if h_t is not None else torch.zeros_like(h)  # 若梯度为空,返回零张量h_x = torch.autograd.grad(h.sum(), x, create_graph=True)  # 计算 ∂h/∂xh_x = h_x[0] if h_x is not None else torch.zeros_like(h)  # 若梯度为空,返回零张量Q_x = torch.autograd.grad(Q.sum(), x, create_graph=True)  # 计算 ∂Q/∂xQ_x = Q_x[0] if Q_x is not None else torch.zeros_like(Q)  # 若梯度为空,返回零张量Q_t = torch.autograd.grad(Q.sum(), t, create_graph=True)  # 计算 ∂Q/∂tQ_t = Q_t[0] if Q_t is not None else torch.zeros_like(Q)  # 若梯度为空,返回零张量Q2_A = Q ** 2 / (A + eps)  # 计算 Q^2/A,添加偏移避免除零Q2_A_x = torch.autograd.grad(Q2_A.sum(), x, create_graph=True)  # 计算 ∂(Q^2/A)/∂xQ2_A_x = Q2_A_x[0] if Q2_A_x is not None else torch.zeros_like(Q)  # 若梯度为空,返回零张量S_f = (n ** 2 * Q * torch.abs(Q)) / (A ** 2 * R ** (4 / 3) + eps)  # 摩擦坡度,添加偏移f1 = (width * h_t) + Q_x  # 质量守恒方程f2 = Q_t + Q2_A_x + g * A * (h_x + S_f - S0)  # 动量守恒方程return f1, f2  # 返回残差# 数据生成函数
def generate_data(N_u=1200, N_c=150000, N_val=100):"""生成训练数据、配准点和验证点,模拟2km河道洪水波"""t = torch.linspace(0, 12000, N_u // 2, device=device, dtype=torch.float32).reshape(-1, 1)  # 生成时间序列x_train = torch.cat([torch.zeros_like(t), 2000 * torch.ones_like(t)], dim=0)  # 设置x=0m和x=2000mt_train = torch.cat([t, t], dim=0)  # 拼接完整时间序列h_train = torch.zeros_like(t_train)  # 初始化水深数组mask1 = t_train <= 6000  # 上升阶段mask2 = (t_train > 6000) & (t_train <= 9000)  # 下降阶段mask3 = t_train > 9000  # 平稳阶段h_train[mask1] = (1.000735) ** (t_train[mask1] / 10) * 0.4  # 上升阶段水深h_ta = (1.000735) ** (6000 / 10) * 0.4  # t=6000s参考值h_train[mask2] = (0.9985) ** ((t_train[mask2] - 6000) / 10) * h_ta  # 下降阶段水深h_train[mask3] = 0.4  # 平稳阶段水深A0 = h_train * 2.0 + 1e-6  # 初始横截面积P0 = 2 * h_train + 2.0 + 1e-6  # 初始湿周长Q_train = ((0.0025) ** 0.5 / 0.02) * (A0 ** (5 / 3)) / (P0 ** (2 / 3))  # 稳态流量x_c = torch.rand(N_c, 1, device=device, dtype=torch.float32) * 2000  # 配准点空间t_c = torch.rand(N_c, 1, device=device, dtype=torch.float32) * 12000  # 配准点时间x_val = torch.tensor([500, 1000, 1500], device=device, dtype=torch.float32).repeat(N_val).reshape(-1, 1)  # 验证点位置t_val = torch.linspace(0, 12000, N_val, device=device, dtype=torch.float32).repeat(3).reshape(-1, 1)  # 验证点时间return (x_train.requires_grad_(True), t_train.requires_grad_(True), h_train, Q_train), \(x_c.requires_grad_(True), t_c.requires_grad_(True)), \(x_val.requires_grad_(True), t_val.requires_grad_(True))# 定义PINN模型(架构C)
class PINN_C(nn.Module):def __init__(self, hidden_layers=8, neurons=20):"""定义架构C的神经网络:输入[x, t, Δh_t],输出[h, Q]"""super(PINN_C, self).__init__()layers = [nn.Linear(3, neurons), nn.Tanh()]  # 输入层:3维 -> neurons,使用tanh激活for _ in range(hidden_layers - 1):layers += [nn.Linear(neurons, neurons), nn.Tanh()]  # 添加隐层layers += [nn.Linear(neurons, 2)]  # 输出层:neurons -> 2 (h, Q)self.net = nn.Sequential(*layers).to(device)  # 构建网络并移到GPUself.S0 = nn.Parameter(torch.tensor([0.002], device=device, dtype=torch.float32))  # 初始化床坡self.n = nn.Parameter(torch.tensor([0.03], device=device, dtype=torch.float32))  # 初始化曼宁系数def forward(self, x, t, dh_dt):"""前向传播,输入[x, t, Δh_t],输出[h, Q]"""inputs = torch.cat([x, t, dh_dt], dim=1)  # 拼接输入向量out = self.net(inputs)  # 通过神经网络h = torch.relu(out[:, 0:1]) + 0.01  # 输出水深,确保非负并加偏移Q = torch.relu(out[:, 1:2]) + 0.01  # 输出流量,确保非负并加偏移return h, Q# 损失函数
def loss_fn_C(model, x_u, t_u, h_u, Q_u, x_c, t_c, mu, sigma):"""计算损失函数,包括数据项、物理项、正则化项和导数惩罚项"""dh_dt_u = torch.zeros_like(h_u)  # 初始化训练数据的 Δh_tdh_dt_u[1:] = (h_u[1:] - h_u[:-1]) / 10  # 计算数值导数dh_dt_u[0] = dh_dt_u[1]  # 边界填充h_pred, Q_pred = model(x_u, t_u, dh_dt_u)  # 预测训练点的 h 和 Qmse_u = torch.mean((h_pred - h_u) ** 2 + (Q_pred - Q_u) ** 2)  # 计算数据误差dh_dt_c = torch.zeros_like(x_c)  # 初始化配准点的 Δh_th_c, Q_c = model(x_c, t_c, dh_dt_c)  # 预测配准点的 h 和 Qf1, f2 = saint_venant_equations(h_c, Q_c, x_c, t_c, model.S0, model.n)  # 计算PDE残差mse_p = torch.mean(f1 ** 2) + torch.mean(f2 ** 2)  # 计算物理误差reg = (1 / (sigma[0] ** 2 + 1e-6)) * (model.S0 - mu[0]) ** 2 + \(1 / (sigma[1] ** 2 + 1e-6)) * (model.n - mu[1]) ** 2  # 参数正则化项h_t = torch.autograd.grad(h_c.sum(), t_c, create_graph=True)  # 计算配准点 ∂h/∂th_t = h_t[0] if h_t is not None else torch.zeros_like(h_c)  # 若梯度为空,返回零张量penalty = torch.mean((h_t - dh_dt_c) ** 2)  # 计算导数惩罚项return mse_u + mse_p + reg + penalty  # 返回总损失# 验证MSE计算
def compute_validation_mse(model, x_val, t_val, h_true, Q_true):"""计算验证点的MSE"""dh_dt_val = torch.zeros_like(h_true)  # 初始化验证点 Δh_tdh_dt_val[1:] = (h_true[1:] - h_true[:-1]) / 10  # 计算数值导数dh_dt_val[0] = dh_dt_val[1]  # 边界填充with torch.no_grad():  # 无梯度计算h_pred, Q_pred = model(x_val, t_val, dh_dt_val)  # 预测验证点 h 和 Qmse_val = torch.mean((h_pred - h_true) ** 2 + (Q_pred - Q_true) ** 2)  # 计算MSEreturn mse_val.item()  # 返回标量值# 训练函数
def train_model(model, x_u, t_u, h_u, Q_u, x_c, t_c, x_val, t_val, h_val, Q_val):"""训练模型:2000次ADAM + 5000次L-BFGS,全部在GPU上"""optimizer_adam = torch.optim.Adam(model.parameters(), lr=0.0001)  # 初始化ADAM优化器optimizer_lbfgs = LBFGS(model.parameters(), lr=0.1, max_iter=20)  # 初始化GPU支持的L-BFGSmu = torch.tensor([0.002, 0.03], device=device, dtype=torch.float32)  # 初始化先验均值sigma = torch.tensor([4.17e-4, 5e-3], device=device, dtype=torch.float32)  # 初始化先验方差S0_history, n_history, losses, val_mses = [], [], [], []  # 初始化历史记录列表print("Training with ADAM on GPU (2000 epochs)...")start_time = time()  # 记录ADAM阶段开始时间for epoch in range(2000):  # 2000次ADAM迭代optimizer_adam.zero_grad()  # 清零梯度loss = loss_fn_C(model, x_u, t_u, h_u, Q_u, x_c, t_c, mu, sigma)  # 计算总损失if torch.isnan(loss):  # 检查是否出现NaNprint(f"NaN detected at epoch {epoch}")breakloss.backward()  # 反向传播torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)  # 梯度裁剪optimizer_adam.step()  # 更新参数S0_history.append(model.S0.item())  # 记录床坡n_history.append(model.n.item())  # 记录曼宁系数losses.append(loss.item())  # 记录损失mu[0] = torch.tensor(S0_history, device=device, dtype=torch.float32).mean()  # 更新S0均值mu[1] = torch.tensor(n_history, device=device, dtype=torch.float32).mean()  # 更新n均值sigma[0] = max((max(S0_history) - min(S0_history)) / 6, 1e-6)  # 更新S0方差sigma[1] = max((max(n_history) - min(n_history)) / 6, 1e-6)  # 更新n方差val_mse = compute_validation_mse(model, x_val, t_val, h_val, Q_val)  # 计算验证MSEval_mses.append(val_mse)  # 记录验证MSEif epoch % 200 == 0:  # 每200次打印结果print(f"Epoch {epoch}, Loss: {loss.item():.6f}, Val MSE: {val_mse:.6f}, "f"S0: {model.S0.item():.6f}, n: {model.n.item():.6f}")print(f"ADAM Training Time: {time() - start_time:.2f}s")  # 打印ADAM阶段时间print("Training with L-BFGS on GPU (5000 epochs)...")start_time = time()  # 记录L-BFGS阶段开始时间def closure():  # 定义L-BFGS闭包函数optimizer_lbfgs.zero_grad()  # 清零梯度loss = loss_fn_C(model, x_u, t_u, h_u, Q_u, x_c, t_c, mu, sigma)  # 计算总损失if torch.isnan(loss):  # 检查是否出现NaNprint("NaN detected in L-BFGS")return lossloss.backward()  # 反向传播return lossfor epoch in range(5000):  # 5000次L-BFGS迭代loss = optimizer_lbfgs.step(closure)  # 执行一步优化if torch.isnan(loss):  # 检查是否出现NaNprint(f"NaN detected at epoch {epoch + 2000}")breakS0_history.append(model.S0.item())  # 记录床坡n_history.append(model.n.item())  # 记录曼宁系数losses.append(loss.item())  # 记录损失mu[0] = torch.tensor(S0_history, device=device, dtype=torch.float32).mean()  # 更新S0均值mu[1] = torch.tensor(n_history, device=device, dtype=torch.float32).mean()  # 更新n均值sigma[0] = max((max(S0_history) - min(S0_history)) / 6, 1e-6)  # 更新S0方差sigma[1] = max((max(n_history) - min(n_history)) / 6, 1e-6)  # 更新n方差val_mse = compute_validation_mse(model, x_val, t_val, h_val, Q_val)  # 计算验证MSEval_mses.append(val_mse)  # 记录验证MSEif (epoch + 2000) % 500 == 0:  # 每500次打印结果print(f"Epoch {epoch + 2000}, Loss: {loss.item():.6f}, Val MSE: {val_mse:.6f}, "f"S0: {model.S0.item():.6f}, n: {model.n.item():.6f}")print(f"L-BFGS Training Time: {time() - start_time:.2f}s")  # 打印L-BFGS阶段时间return losses, val_mses, S0_history, n_history  # 返回训练历史# 可视化结果
def plot_results(model, x_u, t_u, h_u, Q_u, x_val, t_val, losses, val_mses, S0_history, n_history):"""绘制训练结果"""x_u, t_u, h_u = x_u.to('cpu'), t_u.to('cpu'), h_u.to('cpu')  # 数据移到CPU用于绘图dh_dt_u = torch.zeros_like(h_u)  # 初始化 Δh_tdh_dt_u[1:] = (h_u[1:] - h_u[:-1]) / 10  # 计算数值导数dh_dt_u[0] = dh_dt_u[1]  # 边界填充with torch.no_grad():  # 无梯度计算model = model.to('cpu')  # 模型移到CPUh_pred, Q_pred = model(x_u, t_u, dh_dt_u)  # 预测 h 和 Qh_u, Q_u = h_u.numpy(), Q_u.numpy()  # 转换为NumPy数组h_pred, Q_pred = h_pred.numpy(), Q_pred.numpy()  # 同上t_u = t_u.numpy()  # 同上plt.figure(figsize=(15, 10))  # 设置图形大小plt.subplot(2, 2, 1)  # 子图1:损失曲线plt.plot(losses, label='Loss')  # 绘制总损失plt.plot(val_mses, label='Validation MSE')  # 绘制验证MSEplt.xlabel('Epoch')  # x轴标签plt.ylabel('Value')  # y轴标签plt.yscale('log')  # 对数刻度plt.legend()  # 添加图例plt.subplot(2, 2, 2)  # 子图2:流量预测plt.plot(t_u[:len(t_u) // 2], Q_u[:len(t_u) // 2], label='True Q (x=0)')  # 真实流量plt.plot(t_u[:len(t_u) // 2], Q_pred[:len(t_u) // 2], '--', label='Pred Q (x=0)')  # 预测流量plt.xlabel('Time (s)')  # x轴标签plt.ylabel('Flow Rate (m^3/s)')  # y轴标签plt.legend()  # 添加图例plt.subplot(2, 2, 3)  # 子图3:水深预测plt.plot(t_u[:len(t_u) // 2], h_u[:len(t_u) // 2], label='True h (x=0)')  # 真实水深plt.plot(t_u[:len(t_u) // 2], h_pred[:len(t_u) // 2], '--', label='Pred h (x=0)')  # 预测水深plt.xlabel('Time (s)')  # x轴标签plt.ylabel('Water Depth (m)')  # y轴标签plt.legend()  # 添加图例plt.subplot(2, 2, 4)  # 子图4:参数估计plt.plot(S0_history, label='S0')  # 绘制床坡估计plt.plot(n_history, label='n')  # 绘制曼宁系数估计plt.axhline(y=0.0025, color='r', linestyle='--', label='True S0')  # 真实床坡plt.axhline(y=0.02, color='g', linestyle='--', label='True n')  # 真实曼宁系数plt.xlabel('Epoch')  # x轴标签plt.ylabel('Parameter Value')  # y轴标签plt.legend()  # 添加图例plt.tight_layout()  # 调整布局plt.show()  # 显示图形# 主程序
if __name__ == "__main__":(x_u, t_u, h_u, Q_u), (x_c, t_c), (x_val, t_val) = generate_data()  # 生成数据h_val = h_u[:300]  # 设置验证集水深Q_val = Q_u[:300]  # 设置验证集流量model = PINN_C().to(device)  # 初始化模型并移到GPUlosses, val_mses, S0_history, n_history = train_model(model, x_u, t_u, h_u, Q_u, x_c, t_c, x_val, t_val, h_val,Q_val)  # 训练模型plot_results(model, x_u, t_u, h_u, Q_u, x_val, t_val, losses, val_mses, S0_history, n_history)  # 可视化结果print(f"Final S0: {model.S0.item():.6f}, True S0: 0.0025")  # 打印最终床坡估计print(f"Final n: {model.n.item():.6f}, True n: 0.02")  # 打印最终曼宁系数估计print(f"Final Validation MSE: {val_mses[-1]:.6f}")  # 打印最终验证MSE

结论

本论文将PINNs作为河流水流率的替代水文模型,研究其在模拟环境中的性能。结果表明PINNs可同化数据并发现控制系统动力学的微分方程参数,能规避概念模型中参数估计的劣势和经验方法中数据缺乏的问题。且在不同条件下,架构A和架构C的PINNs模型分别有较好表现。

后续展望

作者认为未来可将PINNs应用于解决流域的实时系统。此外,进一步探索PINNs在不同真实世界场景中的应用和深入研究物理和数据学习平衡任务的理论。之后可以优化架构C中参数方差的值以提高系统预测能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21796.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 配置文件

介绍 配置文件时用来解决硬编码问题&#xff0c;把可能会发生改变的信息放在一个集中的地方也就说配置文件上&#xff0c;当我们启动某个程序的时候&#xff0c;应用程序会从配置文件中读取数据&#xff0c;并加载运行。 硬编码是指将数据直接嵌入到源代码中&#xff0c;也就…

Redis三剑客解决方案

文章目录 缓存穿透缓存穿透的概念两种解决方案: 缓存雪崩缓存击穿 缓存穿透 缓存穿透的概念 每一次查询的 key 都不在 redis 中&#xff0c;数据库中也没有。 一般都是属于非法的请求&#xff0c;比如 id<0&#xff0c;比如可以在 API 入口做一些参数校验。 大量访问不存…

LeeCode题库第二十八题

28.找出字符串第一个匹配项的下标 项目场景&#xff1a; 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 …

亚马逊AI图像模型Nova深度体验(含源代码)(上)

在本系列的上篇中&#xff0c;我们介绍了如何利用Amazon Nova Canvas进行创意图片内容生成&#xff0c;并使用Amazon Bedrock的InvokeModel API进行文本到图像&#xff08;文生图&#xff09;的生成。并且介绍了Nova Canvas提供的广泛的功能&#xff0c;包括图像修复、画布扩展…

【MySQL】第八弹---全面解析数据库表的增删改查操作:从创建到检索、排序与分页

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】 目录 1 表的增删改查 1.1 Create 1.1.1 单行数据 全列插入 1.1.2 多行数据 指定列插入 1.1.3 插入否则更新 1.1.4 替…

标量化rknn的输入输出向量转换处理

这是一篇技术探索。yolo11模型生成后&#xff0c;我发现它无法在rknn环境正确识别出目标对象。而在宿主机上&#xff0c;或者直接调用.pt转换过的.onnx模型是可以得到正确结果的。这篇文章对应近乎一天的工作。最终的结论就是。这是一个模型量化的问题&#xff0c;与yolo的版本…

边缘安全加速(Edge Security Acceleration)

边缘安全加速&#xff08;Edge Security Acceleration&#xff0c;简称ESA&#xff09;是一种通过将安全功能与网络边缘紧密结合来提升安全性和加速网络流量的技术。ESA的目标是将安全措施部署到接近用户或设备的地方&#xff0c;通常是在网络的边缘&#xff0c;而不是将所有流…

图表控件Aspose.Diagram入门教程:使用 Python 将 VSDX 转换为 PDF

将VSDX转换为PDF可让用户轻松共享图表。PDF 文件保留原始文档的布局和设计。它们广泛用于演示文稿、报告和文档。在这篇博文中&#xff0c;我们将探讨如何在 Python 中将 VSDX 转换为 PDF。 本文涵盖以下主题&#xff1a; Python VSDX 到 PDF 转换器库使用 Python 将 VSDX 转…

两相四线步进电机的步距角为什么是1.8度

机缘 在CSDN查了好多文章&#xff0c;发现都是用公式来解释1.8的步距角&#xff08;Q&#xff1d;360&#xff0f;MZ&#xff09;&#xff0c;因为转子是50齿&#xff0c;4拍一个循环&#xff0c;所以θ360度/&#xff08;50x4&#xff09;1.8度。估计第一次接触步进电机的什么…

Helix——Figure 02发布通用人形机器人控制的VLA:一组神经网络权重下的快与慢双系统,让两个机器人协作干活

前言 过去一周&#xff0c;我花了很大的心思、力气&#xff0c;把deepseek的GRPO、MLA算法的代码解析通透&#xff0c;比如GRPO与PPO的详细对比&#xff0c;再比如MLA中&#xff0c;图片 公式 代码的一一对应 2.20日晚&#xff0c;无意中刷到figure 02发布Helix的一个演示视频…

Unity游戏制作中的C#基础(2)变量与数据类型

1.变量 &#xff08;1&#xff09;变量的定义&#xff1a;变量是用于存储数据的容器。 &#xff08;2&#xff09;变量的作用&#xff1a;在程序运行过程中&#xff0c;我们可以将各种类型的数据存储在变量中&#xff0c;方便后续使用和操作。 &#xff08;3&#xff09;变量…

革新之力:数字科技——重塑未来的超越想象之旅

在21世纪的科技浪潮中&#xff0c;数字科技如同一股不可阻挡的洪流&#xff0c;正以前所未有的速度和广度改变着我们的生活、工作乃至整个社会的结构。它不仅是技术的简单迭代&#xff0c;更是对人类社会认知边界的拓宽&#xff0c;对经济模式、社会治理、文化形态等多方面的深…

python pandas下载

pandas pandas:就是一个可以处理数据的 python 库 核心功能&#xff1a; 数据的清洗&#xff1a;处理丢失值&#xff0c;重复值数据分析&#xff1a;计算和统计信息&#xff0c;或分组汇总数据可视化&#xff1a;结合 图标库&#xff08;Matplotlib&#xff09;完成数据可视化…

将Google文档导入WordPress:简单实用的几种方法

Google文档是内容创作者非常实用的写作工具。它支持在线编辑、多人协作&#xff0c;并能够自动保存内容。但当我们想把Google文档中的内容导入WordPress网站时&#xff0c;可能会遇到一些小麻烦&#xff0c;比如格式错乱、图片丢失等问题。本文将为大家介绍几种简单实用的方法&…

java面试场景问题

还在补充&#xff0c;这几天工作忙&#xff0c;闲了会把答案附上去&#xff0c;也欢迎各位大佬评论区讨论 1.不用分布式锁如何防重复提交 方法 1&#xff1a;基于唯一请求 ID&#xff08;幂等 Token&#xff09; 思路&#xff1a;前端生成 一个唯一的 requestId&#xff08;…

【笔记ing】C语言补充、组成原理数据表示与汇编实战、操作系统文件实战(高级阶段)

【第19节 C语言语法进阶】 【19.1 条件运算符与逗号运算符】 1 条件运算符 条件运算符是C语言中唯一的一种三亩运算符。三目运算符代表有三个操作数&#xff1b;双目运算符代表有两个操作数&#xff0c;如逻辑运算符就是双目运算符&#xff1b;弹幕运算符代表有一个操作数&a…

GAMES101-现代计算机图形学入门笔记

主讲老师&#xff1a;闫令琪&#xff0c;此处仅做个人笔记使用。如果我的分享对你有帮助&#xff0c;请记得点赞关注不迷路。 课程链接如下&#xff1a;GAMES101-现代计算机图形学入门-闫令琪_哔哩哔哩_bilibili 课程分为四部分&#xff1a;光栅化、几何、光线追踪、模拟 图形…

激光工控机在自动化生产线中有什么关键作用?

激光工控机作为自动化生产线的核心设备&#xff0c;通过高精度控制、快速响应和智能化集成&#xff0c;在提升效率、保障质量、实现柔性制造等方面发挥着不可替代的作用。以下是其关键作用的具体分析&#xff1a; 一、实现高效连续生产&#xff1a; 1.高速加工能力&#xff1…

高等数学(上)题型笔记(六)定积分的应用

目录 1 三角函数定积分的结论 2 定积分的微元法&#xff08;元素法&#xff09; 2.1 使用条件 2.2 使用步骤 3 定积分的几何应用 3.1 平面图形的面积 3.1.1 直角坐标系的情形 3.1.1.1 X型 3.1.1.2 Y型 3.1.1.3 双型 3.1.1.4 复合&#xff1a;分割型 3.1.1.5 引入参…

QT项目——天气预报

文章目录 前言一、项目介绍二、项目基础知识1. 软件开发网络通信架构1.1 CS架构 / BS架构1.1.1 CS架构&#xff08;客户端-服务器架构&#xff09;1.1.2 BS架构&#xff08;浏览器-服务器架构&#xff09; 1.2 HTTP 基本概念 2. QT 下 HTTP 编程2.1 类的解析2.2 示例程序 3. JS…