ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

物理信息神经网络(PINN)原理与PyTorch实战:从伯格斯方程求解到高级优化

物理信息神经网络(PINN)原理与PyTorch实战:从伯格斯方程求解到高级优化 简介本资源是一套面向深度学习与计算数学交叉领域学习者的Python实践教程聚焦物理信息神经网络PINN在微分方程求解中的原理实现与工程落地。针对传统数值方法在高维、稀疏数据或逆问题中面临的瓶颈提供从理论建模到代码训练的完整技术路径特别适合具备基础Python和微分方程知识的进阶学习者开展自主实验与科研复现。压缩包共27个文件以17个Jupyter Notebook为核心——涵盖泊松方程、拉普拉斯方程、扩散方程、欧拉梁、洛伦兹系统等十余类典型PDE/ODE案例辅以3个Python模块文件model.py、geometry.py、PDE.py封装网络构建与几何定义逻辑1个PNG可视化结果图及README说明文档整体仅1.02MB轻量易部署。已有91人下载学习内容结构清晰、案例覆盖广、代码即开即跑可直接用于理解损失函数设计、自动微分嵌入、边界条件编码等PINN关键技术环节。1. 项目概述当神经网络遇见物理定律最近几年在科学计算和工程仿真领域一个结合了深度学习和传统物理建模的方法正变得越来越火那就是物理信息神经网络。我第一次接触这个概念是在尝试解决一个复杂的流体动力学反问题时传统的数值方法要么计算量巨大要么对噪声数据束手无策。PINN提供了一种全新的思路它不直接离散化微分方程而是训练一个神经网络让它“学会”满足特定的物理定律。简单来说你可以把它想象成聘请一个极其聪明的“实习生”——这个实习生神经网络的任务不是去死记硬背方程的解而是去理解方程本身物理定律然后自己推导出在给定边界和初始条件下这个方程应该长什么样。它的核心价值在于解决那些传统方法头疼的问题。比如你只有一些稀疏的、带噪声的观测数据想反推整个物理场的分布或者你的问题域几何形状极其不规则网格划分让人崩溃。PINN通过将物理方程作为“软约束”直接嵌入到神经网络的损失函数中让网络在训练过程中自然而然地遵守这些定律。这意味着你不需要海量的、高精度的标注数据这在科学实验中往往极其昂贵只需要方程本身和少量的边界/初始条件就能训练出一个代理模型。这个模型不仅能给出解还能自动满足微分方程这对于参数反演、模型发现和数据同化等场景来说简直是“降维打击”。无论你是计算物理、流体力学、固体力学的研究人员还是对AI for Science感兴趣的算法工程师或者是在校学生想找一个有深度的课题PINN都值得你投入时间。它不需要你从头推导复杂的数值格式但要求你对自动微分、神经网络训练有基本的了解。接下来我会拆解整个实现流程从原理到代码并分享我趟过的那些坑。2. 核心原理与设计思路拆解2.1 PINN究竟在解决什么问题要理解PINN得先看看我们传统上是怎么对付微分方程的。无论是有限元、有限体积还是有限差分核心思想都是“离散化”把连续的时空区域切成一个个小格子网格然后在每个格点上近似求解方程。这个方法很成熟但有几个天生的短板一是对复杂几何形状的网格生成本身就是一门学问二是对于高维问题比如包含多个参数或时间维度计算量会指数级增长维度灾难三是处理反问题时通常需要反复运行正演模型计算成本高昂。PINN跳出了这个框架。它把微分方程的解u(x, t)用一个神经网络NN(x, t; θ)来参数化其中θ是神经网络的权重和偏置。我们的目标不再是寻找网格点上的数值而是寻找一组最优的网络参数θ*使得神经网络NN的输出尽可能同时满足两件事1. 在已知数据点如边界、初始条件或稀疏观测点上它的输出要和真实值匹配2. 在定义域内部任意点由NN计算出的导数通过自动微分获得要满足给定的物理方程f(x, t, u, u_x, u_t, ...) 0。举个例子对于一维伯格斯方程u_t u * u_x - ν * u_xx 0。我们构建一个神经网络NN(x, t)来预测u。损失函数就会包含两部分数据损失在初始时刻t0和边界x0, xL处网络预测值NN(x,t)与已知条件u_initial(x),u_boundary(t)的均方误差。物理损失在定义域内随机采样一大批“残差点”(x_i, t_i)计算这些点上网络输出对应的导数NN_t,NN_x,NN_xx用TensorFlow/PyTorch的自动微分然后代入伯格斯方程计算残差|NN_t NN * NN_x - ν * NN_xx|^2的均值。总损失就是这两部分的加权和。训练过程就是调整θ最小化这个总损失。当损失收敛到一个很小的值我们就得到了一个近似解u ≈ NN(x, t; θ*)。这个解处处连续可微并且天生满足物理方程。2.2 为什么是神经网络关键优势与潜在挑战选择神经网络作为函数逼近器有几个关键考量万能逼近定理理论上足够深的神经网络可以以任意精度逼近任何连续函数。这为表示复杂的解场提供了理论保障。自动微分这是PINN的“发动机”。像PyTorch和TensorFlow这样的框架可以高效、精确地计算神经网络输出对输入的高阶导数这正是构建物理残差项所必需的。你不需要手动推导或离散化导数框架帮你搞定。网格无关性训练点和测试点可以在定义域内任意采样不受结构化网格限制特别适合不规则区域。端到端可微整个模型从输入坐标到物理残差构成一个可微的计算图使得基于梯度的优化如反向传播可以顺畅进行便于求解反问题即同时优化方程参数和网络参数。但是PINN并非银弹它有自己的“脾气”训练难度大损失函数通常由多个竞争项组成数据损失、物理损失、不同区域的物理损失平衡这些损失项的权重是个技术活调不好容易导致训练失败或解不准确。对高频、多尺度特征捕捉能力弱标准的全连接神经网络具有频谱偏差倾向于先学习低频分量。对于解中含有快速变化或激波的问题需要特别的网络结构或训练技巧。计算成本可能很高虽然一次训练后推理速度很快但训练本身需要大量的前向/反向传播并且要在成千上万个残差点上计算高阶导数对算力有要求。我的设计思路是先易后难验证优先。从一个最简单的、有解析解的常微分方程ODE或偏微分方程PDE入手搭建最小可行管道。确保自动微分、损失计算、优化循环都正确无误后再逐步增加问题复杂度。同时要建立可靠的验证机制比如与解析解或高精度数值解对比这是判断PINN是否“学对了”的唯一标准。3. 环境搭建与核心工具链解析3.1 Python环境与深度学习框架选型PINN的实现严重依赖深度学习框架的自动微分功能。目前主流选择是PyTorch和TensorFlow特别是其急切执行模式。我个人更倾向于PyTorch原因在于它的动态图机制让调试非常直观你可以像写普通Python代码一样构建网络和损失函数使用torch.autograd.grad可以灵活地计算任意输出对任意输入的导数这对于复杂PDE项的组合非常友好。TensorFlow 2.x的tf.GradientTape也提供了类似的能力两者在功能上已非常接近。一个干净的起点至关重要。我强烈建议使用Conda或虚拟环境来管理依赖。下面是一个基于Conda的推荐环境配置# 创建并激活一个名为pinn的虚拟环境指定Python版本推荐3.8-3.10 conda create -n pinn python3.9 conda activate pinn # 安装PyTorch请根据你的CUDA版本前往官网获取最新安装命令 # 例如对于CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 安装科学计算和可视化必备库 pip install numpy matplotlib scipy # 可选但非常有用的库用于进度条、更丰富的优化器、超参调优 pip install tqdm tensorboard注意如果你没有NVIDIA GPU或者不想配置CUDA直接安装CPU版本的PyTorch即可pip install torch torchvision torchaudio。对于学习和小规模问题CPU足够。但处理2D/3D时空问题GPU能带来数十倍的训练加速。3.2 辅助工具可视化与实验管理训练一个PINN模型少则几分钟多则数小时甚至几天。没有好的可视化工具你就像在黑暗中摸索。Matplotlib用于绘制最终的解场对比图、损失下降曲线、误差分布图。这是最基本的。TensorBoardPyTorch可以通过torch.utils.tensorboard.SummaryWriter集成。将训练损失、验证误差、甚至中间预测结果实时写入TensorBoard可以让你在训练过程中动态监控及时发现问题比如损失震荡、爆炸或停滞。Weights Biases (WB)如果你需要做大量的超参数实验学习率、网络深度、损失权重等WB是神器。它能自动记录每次实验的配置、代码、指标和输出并生成漂亮的对比图表帮你高效地找到最优配置。我的工作流通常是用Jupyter Notebook或VSCode进行前期探索和代码调试然后用Python脚本进行正式的长时训练配合TensorBoard实时监控关键实验用WB记录。4. 从零实现一个PINN以伯格斯方程为例让我们用一个经典的例子——一维伯格斯方程——来手把手实现一个PINN。伯格斯方程结合了对流和非线性是检验数值方法和PINN的经典算例。4.1 问题定义与网络架构设计我们求解如下形式的伯格斯方程u_t u * u_x ν * u_xx, x ∈ [-1, 1], t ∈ [0, 1] 初始条件 u(x, 0) -sin(π * x) 边界条件 u(-1, t) u(1, t) 0 参数 ν 0.01 / π这个方程有激波形成和扩散的过程解并不平凡。首先定义神经网络。一个经典的选择是深度全连接网络FCN配合激活函数。这里我们使用一个简单的5层网络每层50个神经元。import torch import torch.nn as nn import numpy as np class PINN(nn.Module): def __init__(self, layers): super(PINN, self).__init__() # layers是一个列表例如 [2, 50, 50, 50, 50, 1] # 表示输入维度2 (x, t)4个隐藏层各50维输出维度1 (u) self.linears nn.ModuleList() for i in range(len(layers)-1): self.linears.append(nn.Linear(layers[i], layers[i1])) self.activation nn.Tanh() # 常用Tanh因其导数平滑适合自动微分 def forward(self, x): # 输入x的形状: [batch_size, 2] 列分别是 x 和 t 坐标 for i, linear in enumerate(self.linears[:-1]): x self.activation(linear(x)) # 最后一层不加激活函数线性输出 x self.linears[-1](x) return x为什么用Tanh在PINN中我们经常需要计算高阶导数如二阶导u_xx。ReLU激活函数的二阶导在非零点为零这可能会在物理残差中引入不希望的平坦区域导致训练困难。Tanh或Sin激活函数具有平滑的高阶导数通常表现更好。近年来也有研究使用自适应激活函数或傅里叶特征嵌入来提升性能但对于入门Tanh是一个稳健的起点。4.2 损失函数的精心构建损失函数是PINN的灵魂设计不当会导致训练失败。我们需要计算三部分损失初始条件损失、边界条件损失和物理残差损失。def compute_loss(model, device, nu): model.train() # 1. 初始条件损失在 t0 的线上采样 x_ic torch.rand(N_ic, 1, devicedevice) * 2 - 1 # x in [-1, 1] t_ic torch.zeros(N_ic, 1, devicedevice) xt_ic torch.cat([x_ic, t_ic], dim1) u_pred_ic model(xt_ic) u_true_ic -torch.sin(np.pi * x_ic) # 解析初始条件 loss_ic torch.mean((u_pred_ic - u_true_ic) ** 2) # 2. 边界条件损失在 x-1 和 x1 的边界上采样 # 左边界 x_bc_left -torch.ones(N_bc, 1, devicedevice) t_bc_left torch.rand(N_bc, 1, devicedevice) # t in [0, 1] xt_bc_left torch.cat([x_bc_left, t_bc_left], dim1) u_pred_bc_left model(xt_bc_left) loss_bc_left torch.mean(u_pred_bc_left ** 2) # 边界值应为0 # 右边界 x_bc_right torch.ones(N_bc, 1, devicedevice) t_bc_right torch.rand(N_bc, 1, devicedevice) xt_bc_right torch.cat([x_bc_right, t_bc_right], dim1) u_pred_bc_right model(xt_bc_right) loss_bc_right torch.mean(u_pred_bc_right ** 2) loss_bc loss_bc_left loss_bc_right # 3. 物理残差损失在整个时空域内随机采样“残差点” x_coll torch.rand(N_coll, 1, devicedevice) * 2 - 1 t_coll torch.rand(N_coll, 1, devicedevice) xt_coll torch.cat([x_coll, t_coll], dim1) # 关键需要计算梯度因此设置 requires_gradTrue xt_coll.requires_grad_(True) u_pred model(xt_coll) # 自动微分计算一阶偏导 grad_outputs torch.ones_like(u_pred) u_t torch.autograd.grad(u_pred, t_coll, grad_outputsgrad_outputs, create_graphTrue)[0] u_x torch.autograd.grad(u_pred, x_coll, grad_outputsgrad_outputs, create_graphTrue)[0] # 计算二阶偏导 u_xx u_xx torch.autograd.grad(u_x, x_coll, grad_outputsgrad_outputs, create_graphTrue)[0] # 伯格斯方程残差: f u_t u * u_x - nu * u_xx f u_t u_pred * u_x - nu * u_xx loss_f torch.mean(f ** 2) # 4. 组合总损失 # 权重 lambda_ic, lambda_bc, lambda_f 需要仔细调优 lambda_ic, lambda_bc, lambda_f 1.0, 1.0, 1.0 # 初始可以设为等权 total_loss lambda_ic * loss_ic lambda_bc * loss_bc lambda_f * loss_f return total_loss, loss_ic, loss_bc, loss_f这里有几个至关重要的细节requires_grad_(True)对于计算物理残差的点xt_coll必须显式设置requires_gradTrue否则torch.autograd.grad无法计算其梯度。create_graphTrue在计算一阶导u_x时需要保留计算图因为后续还要对u_x求导得到u_xx。如果忘了设置计算u_xx时会报错。grad_outputstorch.autograd.grad的第一个参数是标量。我们的u_pred是向量所以需要传入一个全1的grad_outputs来指定梯度权重相当于对每个输出分量求和后再求导。损失权重lambda_ic, lambda_bc, lambda_f的平衡是调参的关键。如果物理残差损失loss_f远大于其他网络可能会忽略边界和初始条件。一种常见的策略是使用“自适应权重”或“学习权重”或者在训练初期给数据损失 (ic,bc) 更高的权重。4.3 训练循环与优化策略有了模型和损失函数就可以开始训练了。优化器的选择和学习率调度很重要。def train_pinn(model, device, nu, epochs, lr): model.to(device) # 使用Adam优化器它对PINN这类问题通常比SGD好 optimizer torch.optim.Adam(model.parameters(), lrlr) # 使用学习率衰减在训练后期微调 scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size2000, gamma0.9) loss_history [] for epoch in range(epochs): optimizer.zero_grad() total_loss, loss_ic, loss_bc, loss_f compute_loss(model, device, nu) total_loss.backward() optimizer.step() scheduler.step() if epoch % 100 0: print(fEpoch {epoch:05d} | Total Loss: {total_loss.item():.6e} | fLoss_IC: {loss_ic.item():.6e} | Loss_BC: {loss_bc.item():.6e} | Loss_f: {loss_f.item():.6e}) loss_history.append([epoch, total_loss.item(), loss_ic.item(), loss_bc.item(), loss_f.item()]) return np.array(loss_history)实操心得训练PINN时不要只看总损失。一定要把各个子损失项 (loss_ic,loss_bc,loss_f) 都打印出来监控。如果某个子损失一直不下降很可能意味着对应的约束没有被满足需要检查采样点是否覆盖了相应区域或者调整该子损失的权重。4.4 结果验证与可视化训练完成后我们需要验证模型的精度。对于伯格斯方程我们可以用高精度的有限差分法如谱方法生成一个参考解或者在某些特定时间切片上与已知的近似解比较。def evaluate_and_plot(model, device): model.eval() # 生成测试网格 x torch.linspace(-1, 1, 200, devicedevice) t torch.linspace(0, 1, 100, devicedevice) X, T torch.meshgrid(x, t, indexingij) xt_test torch.stack([X.flatten(), T.flatten()], dim1) with torch.no_grad(): u_pred model(xt_test).reshape(200, 100).cpu().numpy() # 这里假设我们有一个函数 get_reference_solution(x, t) 来获取参考解 # u_ref get_reference_solution(X.numpy(), T.numpy()) # error np.abs(u_pred - u_ref) # 绘制预测解 import matplotlib.pyplot as plt plt.figure(figsize(12, 4)) plt.subplot(1, 3, 1) plt.contourf(T.cpu().numpy(), X.cpu().numpy(), u_pred, levels50, cmapjet) plt.colorbar() plt.xlabel(Time (t)) plt.ylabel(Space (x)) plt.title(PINN Predicted Solution) # 绘制误差如果有参考解 # plt.subplot(1, 3, 2) # plt.contourf(T.cpu().numpy(), X.cpu().numpy(), error, levels50, cmaphot) # plt.colorbar() # plt.xlabel(Time (t)) # plt.ylabel(Space (x)) # plt.title(Absolute Error) # 绘制特定时间切片 plt.subplot(1, 3, 3) time_slices [0.0, 0.25, 0.5, 0.75, 1.0] for t_slice in time_slices: idx int(t_slice * 99) # 找到对应时间索引 plt.plot(x.cpu().numpy(), u_pred[:, idx], labelft{t_slice}) plt.xlabel(Space (x)) plt.ylabel(u(x,t)) plt.legend() plt.title(Solution at Different Times) plt.tight_layout() plt.show()可视化的目的有两个一是直观检查解是否合理是否符合物理直觉如激波是否清晰二是定量评估误差。L2相对误差是一个常用指标error ||u_pred - u_ref||_2 / ||u_ref||_2。5. 高级技巧与性能优化实战当你成功运行了第一个PINN例子后可能会发现一些问题训练慢、精度不够高、对于复杂问题难以收敛。下面分享几个提升PINN性能的实战技巧。5.1 损失权重自适应与梯度平衡PINN训练不稳定的一个核心原因是损失函数中各项的梯度量级差异巨大。物理残差项loss_f通常涉及高阶导数其梯度可能比数据损失loss_ic/bc大好几个数量级导致优化过程被loss_f主导。解决方案1损失权重手动/自动调整手动调整通过观察各个损失的下降曲线手动调整lambda值。例如如果loss_f下降很快但loss_ic不动就增大lambda_ic。自动调整采用如“学习权重”或“基于方差的权重”。一个简单有效的方法是“软注意力”机制或“损失平衡”。例如让每个损失项的权重与其当前梯度范数的倒数成正比。PyTorch中可以实现如下class AdaptiveWeightedLoss(nn.Module): def __init__(self, num_terms): super().__init__() # 将权重作为可学习的参数初始化为0对应权重为1 self.log_weights nn.Parameter(torch.zeros(num_terms)) def forward(self, loss_terms): # loss_terms: 列表包含各个子损失值 [loss_ic, loss_bc, loss_f] weighted_losses [] for i, loss in enumerate(loss_terms): # 使用 exp(-log_weight) 作为权重确保为正数 weight torch.exp(-self.log_weights[i]) weighted_losses.append(weight * loss self.log_weights[i]) # 加上正则项防止权重趋于无穷 total_loss sum(weighted_losses) return total_loss在训练循环中将total_loss lambda_ic*loss_ic ...替换为adaptive_loss AdaptiveWeightedLoss(3); total_loss adaptive_loss([loss_ic, loss_bc, loss_f])。优化器需要同时优化网络参数和这些log_weights。解决方案2梯度裁剪/归一化在反向传播前对每个损失项产生的梯度进行单独裁剪或归一化防止某一项的梯度“淹没”其他项。5.2 采样策略与领域分解在物理域内均匀随机采样 (torch.rand) 是最简单的方式但对于解变化剧烈的区域如激波附近这可能不够高效导致这些关键区域的误差较大。改进策略自适应残差采样在训练过程中动态地在残差|f|大的区域增加采样点密度。可以每隔一定epoch计算当前模型在一批样本点上的残差选择残差最大的前K%的点在这些点附近进行新一轮采样。重要性采样根据解的先验知识如果有在预期变化大的区域预设更高的采样概率。领域分解对于大尺度或几何复杂的问题可以训练多个子网络每个网络负责一个子区域并在子区域边界上施加连续性/光滑性约束。这能显著降低单个网络的建模难度。5.3 网络架构创新傅里叶特征嵌入与修改激活函数标准全连接网络在拟合高频信号时存在困难。一个有效的技巧是傅里叶特征嵌入。在将坐标(x, t)输入网络之前先将其映射到高频空间class FourierFeatureNet(nn.Module): def __init__(self, in_dim, hidden_layers, out_dim, sigma10.0): super().__init__() # B 是一个随机矩阵决定傅里叶特征的频率 self.B nn.Parameter(sigma * torch.randn(in_dim, hidden_layers[0] // 2), requires_gradFalse) # 通常固定B layers [] dims [hidden_layers[0]] hidden_layers[1:] [out_dim] for i in range(len(dims)-1): layers.append(nn.Linear(dims[i], dims[i1])) if i len(dims)-2: layers.append(nn.Tanh()) self.net nn.Sequential(*layers) def forward(self, x): # x: [batch, in_dim] # 傅里叶特征映射: [sin(2πBx), cos(2πBx)] x_proj 2 * torch.pi * x self.B x_embed torch.cat([torch.sin(x_proj), torch.cos(x_proj)], dim-1) return self.net(x_embed)这个简单的变换也称为“位置编码”能极大地提升网络学习高频信息的能力。参数sigma控制了频率范围需要根据问题的特征尺度进行调整。此外可以尝试Sin 激活函数或自适应激活函数如可学习的tanh斜率参数这些都有相关论文支持在某些问题上能提升收敛速度和精度。6. 常见问题排查与调试心得即使按照教程一步步来你的第一个PINN也可能不工作。以下是我在实战中遇到的一些典型问题及解决方法。6.1 训练失败诊断表现象可能原因排查步骤与解决方案损失值NaN1. 学习率过高。2. 网络输出或中间值溢出特别是使用exp等函数。3. 物理方程中存在除以零的风险。1. 将学习率从1e-3降至1e-4或1e-5。2. 在网络输出层后添加torch.clamp或使用更稳定的激活函数。3. 检查物理残差计算代码避免对可能为零的量直接做除法。损失震荡不下降1. 损失权重不平衡优化过程在不同约束间“摇摆”。2. 采样点不足或分布不合理。3. 优化器不合适。1. 打印并监控各个子损失项。尝试自适应权重或手动调整权重。2. 增加残差采样点数量N_coll。尝试自适应采样。3. 尝试使用AdamW或带weight_decay的Adam。物理损失下降但数据损失不降网络找到了一个满足方程的通解但未满足特定的边界/初始条件。数据损失权重过低。显著提高lambda_ic和lambda_bc的权重例如设为lambda_f的10倍或100倍。确保初始/边界采样点覆盖完整。数据损失下降物理损失不降网络简单地在数据点插值没有学到物理规律。物理损失权重过低或网络容量不足。提高lambda_f的权重。增加网络深度或宽度。检查自动微分代码是否正确计算了高阶导数。训练速度极慢1. 每次迭代都在大量点10万上计算高阶导数。2. 未使用GPU。3. 网络过深。1. 使用小批量训练。每次迭代随机从残差点池中采样一小批如1024个点计算损失。2. 将模型和数据移至GPU (model.to(cuda))。3. 对于简单问题先尝试浅层网络如3-4层。解看起来平滑但误差很大网络陷入了局部极小值学到了一个错误的平滑解。常见于对流主导或具有激波的问题。1. 使用傅里叶特征嵌入帮助网络捕捉高频信息。2. 尝试不同的网络初始化如Xavier或Kaiming初始化。3. 在损失函数中加入基于解的一阶导的惩罚项总变差正则化鼓励解在激波处锐利。6.2 调试技巧与最佳实践从小开始逐步验证永远从一个有解析解的简单ODE如u u 0开始。先确保你的PINN能完美复现这个解。然后再过渡到更复杂的PDE。可视化是王道不仅要看损失曲线更要频繁地可视化预测解。训练初期每隔100或1000个epoch就画一次图观察解是如何演化的。这能帮你直观判断是哪里出了问题。检查梯度使用torch.autograd.grad时务必检查计算出的梯度值是否合理。对于简单的测试函数可以手动计算导数进行对比。固定随机种子在调试阶段使用torch.manual_seed(0)和np.random.seed(0)固定随机数种子。这能确保实验可复现便于定位问题。利用TensorBoard将各个损失项、学习率、甚至验证集上的误差都记录到TensorBoard。通过对比不同超参数下的训练曲线你能更快地找到最优配置。PINN是一个强大但需要精心调校的工具。它不像传统的数值方法那样“开箱即用”更像是一门实验科学。理解其原理掌握调试方法你就能用它来解决那些传统方法难以处理的棘手问题。从简单的控制方程开始积累经验逐步挑战更复杂的应用场景这才是掌握PINN的正确路径。本文还有配套的精品资源点击获取
返回列表