PINN求解偏微分方程
创作时间:
作者:
@小白创作中心
PINN求解偏微分方程
引用
CSDN
1.
https://m.blog.csdn.net/weixin_64443786/article/details/144945060
PINN(Physics-Informed Neural Networks)是一种将物理定律嵌入神经网络的新型求解方法,特别适用于偏微分方程的数值求解。本文将详细介绍PINN的基本原理,并通过一个具体的案例展示其在实际问题中的应用。
一、PINN简介
PINN是一种利用神经网络求解偏微分方程的方法,其计算流程图如下图所示,这里以下方偏微分方程为例:
神经网络输入位置x和时间t的值,预测偏微分方程解u在这个时空条件下的数值解。
由上图可知,PINN的损失函数包含两部分内容,一部分来源于训练数据误差,另一部分来源于偏微分方程误差,可以记作以下公式:
其中,
二、偏微分方程实践
考虑偏微分方程如下:
考虑一下边界条件
以上偏微分方程真解为
,在区域[0,1] × [0,1]上随机采样配置点和数据点,其中配置点用来构造PDE损失函数。
三、基于Pytroch实现代码
import torch
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
epochs = 2000 # 训练代数
h = 100 # 画图网格密度
N = 1000 # 内点配置点数
N1 = 100 # 边界点配置点数
N2 = 1000 # PDE数据点
def setup_seed(seed):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
# 设置随机数种子
setup_seed(888888)
# Domain and Sampling
def interior(n=N):
# 内点
x = torch.rand(n, 1)
y = torch.rand(n, 1)
cond = (2 - x ** 2) * torch.exp(-y)
return x.requires_grad_(True), y.requires_grad_(True), cond
def down_yy(n=N1):
# 边界 u_yy(x,0)=x^2
x = torch.rand(n, 1)
y = torch.zeros_like(x)
cond = x ** 2
return x.requires_grad_(True), y.requires_grad_(True), cond
def up_yy(n=N1):
# 边界 u_yy(x,1)=x^2/e
x = torch.rand(n, 1)
y = torch.ones_like(x)
cond = x ** 2 / torch.e
return x.requires_grad_(True), y.requires_grad_(True), cond
def down(n=N1):
# 边界 u(x,0)=x^2
x = torch.rand(n, 1)
y = torch.zeros_like(x)
cond = x ** 2
return x.requires_grad_(True), y.requires_grad_(True), cond
def up(n=N1):
# 边界 u(x,1)=x^2/e
x = torch.rand(n, 1)
y = torch.ones_like(x)
cond = x ** 2 / torch.e
return x.requires_grad_(True), y.requires_grad_(True), cond
def left(n=N1):
# 边界 u(0,y)=0
y = torch.rand(n, 1)
x = torch.zeros_like(y)
cond = torch.zeros_like(x)
return x.requires_grad_(True), y.requires_grad_(True), cond
def right(n=N1):
# 边界 u(1,y)=e^(-y)
y = torch.rand(n, 1)
x = torch.ones_like(y)
cond = torch.exp(-y)
return x.requires_grad_(True), y.requires_grad_(True), cond
def data_interior(n=N2):
# 内点
x = torch.rand(n, 1)
y = torch.rand(n, 1)
cond = (x ** 2) * torch.exp(-y)
return x.requires_grad_(True), y.requires_grad_(True), cond
# Neural Network
class MLP(torch.nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.net = torch.nn.Sequential(
torch.nn.Linear(2, 32),
torch.nn.Tanh(),
torch.nn.Linear(32, 32),
torch.nn.Tanh(),
torch.nn.Linear(32, 32),
torch.nn.Tanh(),
torch.nn.Linear(32, 32),
torch.nn.Tanh(),
torch.nn.Linear(32, 1)
)
def forward(self, x):
return self.net(x)
# Loss
loss = torch.nn.MSELoss()
def gradients(u, x, order=1):
if order == 1:
return torch.autograd.grad(u, x, grad_outputs=torch.ones_like(u),
create_graph=True,
only_inputs=True, )[0]
else:
return gradients(gradients(u, x), x, order=order - 1)
# 以下7个损失是PDE损失
def l_interior(u):
# 损失函数L1
x, y, cond = interior()
uxy = u(torch.cat([x, y], dim=1))
return loss(gradients(uxy, x, 2) - gradients(uxy, y, 4), cond)
def l_down_yy(u):
# 损失函数L2
x, y, cond = down_yy()
uxy = u(torch.cat([x, y], dim=1))
return loss(gradients(uxy, y, 2), cond)
def l_up_yy(u):
# 损失函数L3
x, y, cond = up_yy()
uxy = u(torch.cat([x, y], dim=1))
return loss(gradients(uxy, y, 2), cond)
def l_down(u):
# 损失函数L4
x, y, cond = down()
uxy = u(torch.cat([x, y], dim=1))
return loss(uxy, cond)
def l_up(u):
# 损失函数L5
x, y, cond = up()
uxy = u(torch.cat([x, y], dim=1))
return loss(uxy, cond)
def l_left(u):
# 损失函数L6
x, y, cond = left()
uxy = u(torch.cat([x, y], dim=1))
return loss(uxy, cond)
def l_right(u):
# 损失函数L7
x, y, cond = right()
uxy = u(torch.cat([x, y], dim=1))
return loss(uxy, cond)
# 构造数据损失
def l_data(u):
# 损失函数L8
x, y, cond = data_interior()
uxy = u(torch.cat([x, y], dim=1))
return loss(uxy, cond)
# Training
u = MLP()
opt = torch.optim.Adam(params=u.parameters())
for i in range(epochs):
opt.zero_grad()
l = l_interior(u) \
+ l_up_yy(u) \
+ l_down_yy(u) \
+ l_up(u) \
+ l_down(u) \
+ l_left(u) \
+ l_right(u) \
+ l_data(u)
l.backward()
opt.step()
if i % 100 == 0:
print("Epoch: ", i, "Loss: ", l.item())
# Inference
xc = torch.linspace(0, 1, h)
xm, ym = torch.meshgrid(xc, xc)
xx = xm.reshape(-1, 1)
yy = ym.reshape(-1, 1)
xy = torch.cat([xx, yy], dim=1)
u_pred = u(xy)
u_real = xx * xx * torch.exp(-yy)
u_error = torch.abs(u_pred-u_real)
u_pred_fig = u_pred.reshape(h,h)
u_real_fig = u_real.reshape(h,h)
u_error_fig = u_error.reshape(h,h)
print("Max abs error is: ", float(torch.max(torch.abs(u_pred - xx * xx * torch.exp(-yy)))))
# 仅有PDE损失 Max abs error: 0.004852950572967529
# 带有数据点损失 Max abs error: 0.0018916130065917969
# 作PINN数值解图
fig = plt.figure()
ax = Axes3D(fig)
fig.add_axes(ax)
ax.plot_surface(xm.detach().numpy(), ym.detach().numpy(), u_pred_fig.detach().numpy())
ax.text2D(0.5, 0.9, "PINN", transform=ax.transAxes)
plt.show()
fig.savefig("PINN solve.png")
# 作真解图
fig = plt.figure()
ax = Axes3D(fig)
fig.add_axes(ax)
ax.plot_surface(xm.detach().numpy(), ym.detach().numpy(), u_real_fig.detach().numpy())
ax.text2D(0.5, 0.9, "real solve", transform=ax.transAxes)
plt.show()
fig.savefig("real solve.png")
# 误差图
fig = plt.figure()
ax = Axes3D(fig)
fig.add_axes(ax)
ax.plot_surface(xm.detach().numpy(), ym.detach().numpy(), u_error_fig.detach().numpy())
ax.text2D(0.5, 0.9, "abs error", transform=ax.transAxes)
plt.show()
fig.savefig("abs error.png")
torch.save(u.state_dict(),'model_uxt.pt')
热门推荐
全国计算机等级考试三级网络技术考试大纲
牙龈化脓一般几天能好
C1驾照考试内容及合格标准详解
想运动又怕伤膝盖?这3种运动很“友好”
轻松放倒宝来汽车后排座椅,提升空间利用率!步骤详解!
STM32H7通用定时器计数功能的使用
重庆一小区发通知捕杀流浪猫?物业回应:表述欠缺考虑,已撤回通知
瘦子如何增肌增重?附详细健身和饮食计划
睡眠革命:健康揭秘高质量睡眠的秘密,让好梦伴你每一夜!
《黑神话:悟空》建模图集揭秘:巨灵神和土地庙背后的艺术与技术
防水涂层厚度的选择与施工要求
用了50年才换新列车?伦敦地铁究竟有多老?一文带你了解世界最早的地铁系统!
3D打印创意无限:从作品展示到实用技巧详解
文山学院构建“1234”模式 践行劳动教育“理实”结合
明日方舟终末地战斗机制详解:破防条、元素反应与AI控制
黛力新遇上这些食物,后果堪忧!90%患者竟不知此禁忌!
Intel 14代带K处理器温度过高?微星B760/Z790主板CEP降压指南
顾姓的起源与传承:昆吾氏樊后裔的故事
这些年,外资在A股玩了个寂寞
切不完的肿物,不是恶性肿瘤,而是这种病
梦见屎的周公解梦解析:多重象征意义与现实启示
全方位指南:海南文昌一日游精品路线规划与旅游贴士
新手养狗指南:七种适合入门的小型犬推荐
什么是电动机负载率?详解其定义、计算方法及在电动汽车中的应用
@大龄就业人员 找工作遇到困难?不妨试试这些方法
SaaS产品如何解决定制化需求
乳牙是拔掉还是自然脱落好
刘永谋:AI是否导致人类灭绝,要看我们如何发展和运用AI
世界语是什么
螺栓扭矩系数影响因素的试验研究