方程的选择与处理
首先,选取的偏微分方程参考了如下博客
神经网络学习(三):解偏微分方程_LusinLee的博客-CSDN博客_神经网络求解偏微分方程
这里的偏微分方程为:
在设计损失函数时,我选择了通过改变网络输出函数,使得在计算损失函数时不需要考虑边界条件,相关公式如下:
其中,NN(x,t)为神经网络输出。不难验证,此时的g(x,t)无论NN(x,t)为何值,都必然满足边界条件。只需要:
优化器的选择
在选取优化器时,我遇到了这样的问题:使用SGD得到的结果都比较糟糕,而选择Adam则会得到不错的结果。原因我并不清楚。
网络结构
通常情况下,我们是不知道原函数的值域的。因此在输出层设置激活函数可能会使得网络输出的值永
远无法接近真实值。因此我输出层没有设置激活函数(也许RReLU可以?)。同时,由于不知道原函数的值域,因此输出层前一层的神经元需要多一些,便于拟合值域跨度较大的函数。
反向传播
pytorch在进行反向传播时,.backward()是不能对输入的自变量x,t使用的,此时要使用:
torch.autograd.grad(outputs,inputs,grad_outputs,create_graph=True)。其中,outputs为输出,inputs为输入,grad_outputs需要设置为形状与输出形状相同的全1的tensor。create_graph需设置为真,否则后续无法继续求导
同时需要注意,torch.autograd.grad的返回值不是tensor。torch.autograd.grad()[0]才是所需要的trensor。
最后附上pytorch代码:
#coding:gb2312
import torch
import torch.nn as nn
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
#定义pde类
class pde(torch.nn.Module):
def __init__(self,n_features):
super(pde,self).__init__()
self.main=nn.Sequential(
nn.Linear(2,100),
nn.Tanh(),
nn.Linear(100,100),
nn.Tanh(),
nn.Linear(100,20),
nn.Tanh(),
nn.Linear(20,20),
nn.Tanh(),
nn.Linear(20,1),
)
def forward(self,inputs):
inputs = inputs.to(torch.float32)
out=self.main(inputs)
out=out.reshape(10000)
out=(inputs[:,0]**2-1)*inputs[:,1]*out-torch.sin(3.1415926*inputs[:,0])
out=out.reshape(-1,1)
return out
pdesolver=pde(1)#额,这个1似乎什么作用都没起到……
pdesolver=pdesolver.cuda()
optimizer=torch.optim.Adam(pdesolver.parameters(),lr=0.001)
loss_func=torch.nn.MSELoss()
#以下是在设置自变量x,t的值
xt=np.zeros(10000*2).reshape(10000,2)
temp_j=np.linspace(-1,1,100)
for i in range(100):
xt[i*100:i*100+100,0]=temp_j[i]
xt[i*100:i*100+100,1]=np.linspace(0,1,100)
xt=torch.tensor(xt,requires_grad=True).cuda()
p=1
i=0
while p>0.02:
i+=1
y_pre = pdesolver(xt)
#以下是分别求出各个所需要的偏微分
dy=torch.autograd.grad(outputs=y_pre,inputs=xt,grad_outputs=torch.ones_like(y_pre),create_graph=True)
dyx=(dy[0][:,0]).reshape(-1,1)
dyt=(dy[0][:,1]).reshape(-1,1)
ddy=torch.autograd.grad(outputs=dyx,inputs=xt,grad_outputs=torch.ones_like(y_pre),create_graph=True)
ddyx=ddy[0][:,0].reshape(-1,1)
#偏微分方程的左右两侧
left=dyt+y_pre*dyx
right=0.01/3.1415926*ddyx
loss = loss_func(left.float(),right.float())
p=loss.item()
print(i,p)
optimizer.zero_grad()
loss.backward()
optimizer.step()
#以下就全是可视化了
u=pdesolver(xt)
u=u.reshape(-1)
u=u.reshape(100,100)
u=u.cpu()
u=u.detach().numpy()
x=temp_j
t=np.linspace(0,1,100)
T ,X= np.meshgrid( t,x)
fig = plt.figure()
ax = plt.axes(projection='3d')
print(X)
print(T)
for i in u:
print(i)
ax.plot_surface(X, T, u,cmap='rainbow', edgecolor='none')
plt.show()
结果: