
简介这份资源围绕物理信息神经网络PINN求解微分方程展开面向具备一定Python与深度学习基础、希望将神经网络用于科学计算的研究生、科研人员及算法工程师。内容覆盖常微分方程、扩散方程、泊松方程、拉普拉斯方程及洛伦兹系统等典型问题并涉及Dirichlet、Neumann、Robin、周期等多种边界条件帮助读者理解如何把物理方程约束嵌入损失函数进行求解。资源包共22个文件以17个ipynb交互式笔记本为主体配合3个py脚本、1个md说明文档和1个png结果图压缩包约889KB便于按案例逐个运行与调试。其中脚本涵盖几何采样、PDE构建与模型定义等模块笔记本则给出从简单ODE到偏微分方程系统的完整实现路径并包含Jacobian-Hessian方法等进阶测试。目前已有2974人学习下载适合作为PINN入门到进阶的实践参考。1. 从一份 PINN-Notebooks 压缩包说起它到底能帮你解什么方程如果你正在用 Python 做微分方程数值求解又被网格划分、边界条件适配、高维灾难折腾过那这份基于PINN求解微分方程的方法python.zip值得你花一个下午拆开看。它不是一份只讲概念的 PPT而是一套可以直接在 Jupyter 里跑起来的 Notebook 集合核心是用物理信息神经网络PINN把微分方程残差直接塞进损失函数让网络在训练中同时满足方程和边界条件。压缩包里既有Euler Beam.ipynb、Diffusion equation.ipynb这类经典方程也有Lorenz system.ipynb、PDAE_system.ipynb这种偏工程和动力系统的案例还配了pinns geometry.py、PDE.py、model.py三个基础模块。适合谁适合已经会 Python、懂一点 PyTorch 或 TensorFlow、想快速验证 PINN 在自己方程上能不能跑通的人。如果你连python安装教程都还没走完建议先补环境再回来拆这份资源。2. 拆包先看结构Notebook、模块与几何定义怎么分工2.1 压缩包里的三类文件Notebook、基础模块、辅助脚本拿到压缩包后别急着逐个打开 Notebook先按功能分三类。第一类是Methods Completed目录下的十几个.ipynb每个文件对应一个具体方程或系统比如Poisson_equation_Dirichlet.ipynb、Laplace_equation_on_a_disk.ipynb、y_-y-y2x, x∈[-5,5], y(-5)1, y(5)5.ipynb。这些 Notebook 是主入口里面通常包含方程定义、边界条件、网络搭建、训练循环和可视化。第二类是根目录下的pinns geometry.py、PDE.py、model.py它们把几何采样、PDE 残差计算、网络结构抽象成可复用函数避免每个 Notebook 重复造轮子。第三类是Method Testing目录下的Jacobian-Hessian methods for Laplace equation.ipynb和Jacobian-Hessian methods for ODE system.ipynb以及data_domain.ipynb、robin plot.png、README.md这些偏向方法对比和结果展示。常见做法是先把README.md读一遍确认作者推荐的运行顺序和依赖版本。如果 README 没写就按 Notebook 文件名里的方程复杂度排序先跑A_simple_ODE_system.ipynb和ysin(πx)_cos(πx), x∈[-1,1], y(-1)0.ipynb再跑 Poisson 和 Laplace最后碰PDAE_system.ipynb和Lorenz system.ipynb。这样做的原因是简单方程能帮你快速验证环境是否正常复杂系统一旦报错排查范围会小很多。2.2 三个基础模块的职责边界geometry、PDE、modelpinns geometry.py负责采样点生成。PINN 不需要网格但需要在求解域内随机或均匀撒点边界上也要单独采样。这个文件里通常有矩形域、圆域、区间域的采样函数对应Laplace_equation_on_a_disk.ipynb里的圆盘几何和Poisson_equation_Dirichlet.ipynb里的矩形域。如果你要解自己的方程第一步就是改这里的几何定义把采样范围换成你的x∈[a,b]或Ω。PDE.py负责把微分方程写成残差形式。比如对于-yπ^2*sin(πx)它会在网络输出y后用自动微分算y再和右端项相减得到残差。这个文件是 PINN 的核心因为损失函数里方程残差那一项就靠它。model.py则是网络结构定义通常是全连接网络输入维度等于自变量个数输出维度等于因变量个数。有些 Notebook 会在这里加 Fourier 特征或自适应激活函数但这份资源里大概率是基础 MLP。提示先不要改model.py的网络层数和宽度用默认参数跑通一个 Notebook再根据 loss 曲线决定要不要加深加宽。2.3 从简单 ODE 到 PDE 系统的递进路线这份资源最舒服的地方是它按方程类型排了序。你可以按下面这条路线走每跑通一个再进下一个A_simple_ODE_system.ipynb一阶 ODE 系统用来确认自动微分和损失反传没问题。ysin(πx)_cos(πx), x∈[-1,1], y(-1)0.ipynb带周期右端项的 ODE看边界条件怎么加。y_-y-y2x, x∈[-5,5], y(-5)1, y(5)5.ipynb二阶线性 ODE两个边界条件适合理解 Dirichlet 边界在损失里的权重。Poisson_equation_Dirichlet.ipynb和Laplace_equation_on_a_disk.ipynb二维 PDE开始涉及空间采样和更高维输入。Diffusion equation.ipynb和Euler Beam.ipynb时间相关或四阶方程看 PINN 怎么处理时间维和更高阶导数。Lorenz system.ipynb和PDAE_system.ipynb动力系统和微分代数方程属于进阶内容。每跑一个 Notebook重点看三处训练 loss 是否稳定下降、边界 loss 和方程 loss 的量级是否接近、预测解和解析解或参考解的对比图是否吻合。如果边界 loss 一直比方程 loss 大几个数量级说明边界权重需要调或者边界采样点太少。3. 跑通第一个 Notebook环境、参数与训练循环拆解3.1 环境准备Python、PyTorch 与 Jupyter 的最小依赖这份资源是 Python 写的Notebook 里大概率用 PyTorch 做自动微分。你不需要把python爬虫或python量化交易策略代码那套东西装进来最小依赖就是 Python 3.8、PyTorch、NumPy、Matplotlib、Jupyter Notebook。如果你用vscode python环境配置或pycharm配置python环境确保 Jupyter 内核指向同一个解释器。# 创建独立环境避免和系统 Python 冲突 python -m venv pinn_env source pinn_env/bin/activate # Windows 用 pinn_env\Scripts\activate # 安装最小依赖PyTorch 按官网选择 CPU 或 CUDA 版本 pip install torch numpy matplotlib jupyter # 启动 Notebook jupyter notebook这段命令的逻辑是先隔离环境再装依赖最后启动 Jupyter。参数上python -m venv的pinn_env是环境名你可以改成任何名字。PyTorch 安装命令不要直接抄pip install torch因为 CPU 和 CUDA 版本命令不同去 PyTorch 官网选对应版本更稳。如果你在ubuntu安装docker并运行python环境记得把 Jupyter 的端口映射出来否则浏览器访问不到。注意有些 Notebook 可能用 TensorFlow 或 JAX打开第一个 cell 看 import 语句再决定装哪个。不要同时装 PyTorch 和 TensorFlow 的 GPU 版本容易出动态库冲突。3.2 以简单 ODE 为例方程定义、边界条件与损失函数打开A_simple_ODE_system.ipynb或ysin(πx)_cos(πx), x∈[-1,1], y(-1)0.ipynb你会看到类似下面的结构。这里我用 PyTorch 写一个最小可复现版本逻辑和 Notebook 里一致。import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt # 定义网络输入 x输出 y class PINN(nn.Module): def __init__(self): super().__init__() self.net nn.Sequential( nn.Linear(1, 32), nn.Tanh(), nn.Linear(32, 32), nn.Tanh(), nn.Linear(32, 1) ) def forward(self, x): return self.net(x) # 方程y sin(pi*x)*cos(pi*x)x in [-1,1]y(-1)0 # 解析解y (1/(2*pi))*sin(pi*x)**2 def pde_residual(model, x): x.requires_grad_(True) y model(x) dy_dx torch.autograd.grad(y, x, torch.ones_like(y), create_graphTrue)[0] residual dy_dx - torch.sin(torch.pi * x) * torch.cos(torch.pi * x) return residual model PINN() optimizer torch.optim.Adam(model.parameters(), lr1e-3) # 域内采样点和边界点 x_domain torch.rand(1000, 1) * 2 - 1 # [-1,1] x_boundary torch.tensor([[-1.0]]) y_boundary torch.tensor([[0.0]]) for epoch in range(5000): optimizer.zero_grad() res pde_residual(model, x_domain) loss_pde torch.mean(res ** 2) loss_bc torch.mean((model(x_boundary) - y_boundary) ** 2) loss loss_pde 10.0 * loss_bc # 边界权重 loss.backward() optimizer.step() if epoch % 1000 0: print(fepoch {epoch}, loss_pde {loss_pde.item():.6f}, loss_bc {loss_bc.item():.6f})这段代码的关键点有三个。第一x.requires_grad_(True)必须开否则torch.autograd.grad算不出导数。第二create_graphTrue在算高阶导数时必须加比如二阶 ODE 要算y时第一次求导的结果还要参与第二次求导。第三边界权重10.0是经验值不是固定值。如果边界 loss 下降慢就加大这个权重如果方程 loss 下不去就减小它。Notebook 里通常会把权重写成变量方便你调。3.3 训练循环里的五个可调参数采样数、网络宽度、学习率、权重、迭代次数跑通之后你会想调参。这份资源里每个 Notebook 的参数不完全一样但核心就五个参数常见范围调大后的影响调小后的影响域内采样点数5005000方程残差估计更准但每步更慢训练快但 loss 震荡网络宽度/深度24 层32128 神经元拟合能力强但容易过拟合边界欠拟合loss 下不去学习率1e-41e-2收敛快但可能震荡不收敛稳定但慢边界权重1100边界满足好但方程可能变差方程好边界漂移迭代次数500050000更充分但可能过拟合欠训练我一般会先用默认参数跑 5000 步看 loss 曲线。如果loss_pde和loss_bc都降到 1e-4 以下基本就收敛了。如果loss_bc卡在 1e-2 不动先把边界权重乘 10再跑 2000 步。如果还不行检查边界点是不是只采了一个点有些 Notebook 会在边界上采多个点你改成多个点会更稳。提示python abs函数那种基础语法在这里用不上但torch.abs在自定义损失时可能用到。别把 NumPy 的np.abs和torch.abs混用会报类型错误。4. 从 ODE 到 PDE几何采样、边界类型与 Jacobian-Hessian 方法4.1 二维 Poisson 方程的 Dirichlet、Neumann、Robin、Periodic 边界这份资源里 Poisson 方程有四个变体Poisson_equation_Dirichlet.ipynb、Poisson_equation_Dirichlet_Neumann.ipynb、Poisson_equation_Dirichlet_Robin.ipynb、Poisson_equation_Dirichlet_Periodic.ipynb。它们共用同一个方程Δu f区别在边界条件。Dirichlet 是直接给u的值Neumann 是给法向导数∂u/∂nRobin 是给u和∂u/∂n的线性组合Periodic 是要求边界两侧的值和导数相等。在 PINN 里Dirichlet 边界最容易加直接算model(x_b) - u_b的均方误差。Neumann 边界需要算网络输出对输入的梯度再和给定法向导数比较。Robin 边界要把两项加起来。Periodic 边界要同时算值和导数在两侧的差。常见做法是在PDE.py里为每种边界写一个函数Notebook 里按需调用。# Neumann 边界示例∂u/∂n g(x) def neumann_loss(model, x_b, normal, g): x_b.requires_grad_(True) u model(x_b) grad_u torch.autograd.grad(u, x_b, torch.ones_like(u), create_graphTrue)[0] du_dn torch.sum(grad_u * normal, dim1, keepdimTrue) return torch.mean((du_dn - g) ** 2)这段代码里normal是边界外法向向量g是给定的法向导数。torch.sum(grad_u * normal, dim1)就是方向导数。注意x_b必须重新开requires_grad_因为采样时生成的张量默认不带梯度。4.2 圆盘 Laplace 方程的极坐标采样与几何适配Laplace_equation_on_a_disk.ipynb处理的是圆盘上的 Laplace 方程。圆盘几何不能用矩形均匀采样常见做法是用极坐标(r, θ)采样再转成(x, y)。pinns geometry.py里应该有圆盘采样函数如果没有你可以自己写def sample_disk(n_r, n_theta, radius1.0): r torch.rand(n_r, 1) * radius theta torch.rand(n_theta, 1) * 2 * torch.pi x r * torch.cos(theta) y r * torch.sin(theta) return torch.cat([x, y], dim1) def sample_circle(n, radius1.0): theta torch.rand(n, 1) * 2 * torch.pi x radius * torch.cos(theta) y radius * torch.sin(theta) return torch.cat([x, y], dim1)sample_disk在圆盘内部采样sample_circle在圆周上采样。注意r的采样不能直接用均匀分布否则点会向圆心聚集。更均匀的做法是r radius * torch.sqrt(torch.rand(n_r, 1))这样面积分布均匀。Notebook 里如果没做这个修正你可以自己改否则圆心附近点太多边界附近点太少边界 loss 会难以下降。4.3 Jacobian-Hessian 方法在 Laplace 和 ODE 系统里的测试对比Method Testing目录下的两个 Notebook 专门对比 Jacobian-Hessian 方法。在 PINN 里计算二阶导数有两种方式一种是直接对网络输出做两次自动微分另一种是利用 Jacobian 和 Hessian 的矩阵结构做批量计算。前者简单但慢后者快但实现复杂。这两个 Notebook 的作用是让你看到两种方式在 Laplace 方程和 ODE 系统上的精度和耗时差异。如果你只是解一个简单方程直接用自动微分就行。如果你要解高维 PDE 或需要大量迭代Jacobian-Hessian 方法能省不少时间。常见做法是先用自动微分跑通再换成 Jacobian-Hessian 看加速比。注意这两种方法在数值精度上可能有细微差别尤其是边界附近换方法后要重新检查边界 loss。注意data_domain.ipynb可能是用来生成或可视化采样点的跑之前先确认它依赖的数据文件在不在压缩包里。如果缺文件跳过它不影响其他 Notebook。5. 避坑与排查PINN 训练不收敛时先查这五处5.1 现象loss 一直不降输出全是零或常数原因通常是网络输出被初始化成接近零而方程残差里没有足够的梯度信号。解决方法是换激活函数把Tanh换成Sin或GELU或者把输出层初始化改大一点。另外检查pde_residual里有没有把x.requires_grad_(True)写漏漏了的话梯度算不出来loss 自然不动。5.2 现象边界 loss 降了但方程 loss 反弹这是边界权重过大的典型表现。PINN 的损失是多项加权和边界权重太高网络会优先满足边界而牺牲方程。解决方法是把边界权重从 10 降到 1 或 0.1再跑 2000 步看方程 loss 是否下降。如果降了但边界又漂了就用自适应权重比如每 1000 步根据两项 loss 的比值调整一次。5.3 现象二阶导数算出来是 None 或报错检查torch.autograd.grad里的create_graphTrue有没有加。算一阶导数时如果不需要再求导可以不加但算二阶导数时第一次求导必须保留计算图。另外x必须是浮点张量不能是整数张量否则requires_grad_会报错。5.4 现象圆盘或复杂几何边界点采样不均匀圆盘采样用均匀r会导致圆心密集。改成r R * sqrt(rand)后面积均匀。对于更复杂的几何常见做法是用拒绝采样或网格采样再筛选。如果pinns geometry.py里的采样函数不适用你的几何别硬改自己写一个采样函数替换掉保持接口一致就行。5.5 现象换到 Lorenz 系统或 PDAE 后训练发散Lorenz 系统对初值敏感PDAE 有代数约束这两类问题比前面难。先检查时间步长和采样范围Lorenz 的t范围不要一上来就取很大先取[0, 1]跑通再扩。PDAE 的代数约束要单独加一项 loss权重不能太小。如果发散把学习率降到 1e-4迭代次数加到 50000再看 loss 曲线。6. 进阶技巧用 Jacobian-Hessian 加速并验证你的 PINN跑通几个 Notebook 后你会注意到二阶导数的计算是瓶颈。Method Testing里的 Jacobian-Hessian 方法值得单独拆出来用。我一般会这样做先在一个简单 ODE 上对比两种方法的单步耗时和最终 loss确认加速比和精度损失可接受再换到 PDE 上。# 自动微分算二阶导的耗时测试 import time def autograd_hessian(model, x): x.requires_grad_(True) y model(x) dy torch.autograd.grad(y, x, torch.ones_like(y), create_graphTrue)[0] d2y torch.autograd.grad(dy, x, torch.ones_like(dy), create_graphTrue)[0] return d2y # 跑 100 次取平均 x_test torch.rand(1000, 1) start time.time() for _ in range(100): _ autograd_hessian(model, x_test) print(autograd hessian time:, time.time() - start)这段代码只是测耗时实际训练时要把 Hessian 计算嵌进损失里。Jacobian-Hessian 方法的思路是一次性算出所有输出对输入的偏导矩阵再组合成二阶导减少重复计算。如果你用 PyTorch可以查torch.autograd.functional.hessian但它对批量输入支持有限常见做法还是手写批量 Jacobian。验证方法上我习惯用解析解对比。比如-yπ^2*sin(πx)在[-1,1]上y(-1)0, y(1)0的解析解是ysin(πx)。训练完后在x上均匀取 100 个点算预测值和解析值的最大绝对误差。如果误差在 1e-3 以内说明网络和训练参数都合适。如果误差在边界附近大检查边界权重和边界采样点数量。提示python生成exe可执行文件那套打包方法不适合 Notebook但你可以把训练好的模型参数存成.pt文件再用一个独立脚本加载推理。这样部署时不需要 Jupyter。从那以后我每次拆这类 PINN 资源都强制先跑一个最简单的 ODE确认自动微分和损失反传没问题再碰 PDE 和动力系统。这份PINN-Notebooks-main的排序正好符合这个习惯你按它的文件名顺序走能省不少排查时间。希望帮到你。本文还有配套的精品资源点击获取