[Python] Implement Physics informed Neural Network using pytorch

Discussão em 'Python' iniciado por Stack, Março 18, 2025.

  1. Stack

    Stack Membro Participativo

    I found a very interesting paper, Physics Informed Deep Learning (Part I): Data-driven Solutions of Nonlinear Partial Differential Equations and want to give it a trial. For this, I create a dummy problem and implement what I understand from the paper.

    Problem Statement


    Suppose, I want to solve the ODE dy/dx = cos(x) with initial conditions y(0)=y(2*pi)=0. Actually, we can easily guess the analytic solution y(x)=sin(x). But I want to see how the model predict the solution using PINN.

    # import libraries
    import torch
    import torch.autograd as autograd # computation graph
    import torch.nn as nn # neural networks
    import torch.optim as optim # optimizers e.g. gradient descent, ADAM, etc.
    import matplotlib.pyplot as plt
    import numpy as np

    #Set default dtype to float32
    torch.set_default_dtype(torch.float)
    #PyTorch random number generator
    torch.manual_seed(1234)
    # Device configuration
    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
    print(device)

    Model Architecture


    ## Model Architecture
    class FCN(nn.Module):
    ##Neural Network
    def __init__(self,layers):
    super().__init__() #call __init__ from parent class
    # activation function
    self.activation = nn.Tanh()
    # loss function
    self.loss_function = nn.MSELoss(reduction ='mean')
    # Initialise neural network as a list using nn.Modulelist
    self.linears = nn.ModuleList([nn.Linear(layers, layers[i+1]) for i in range(len(layers)-1)])
    self.iter = 0
    # Xavier Normal Initialization
    for i in range(len(layers)-1):
    nn.init.xavier_normal_(self.linears.weight.data, gain=1.0)
    # set biases to zero
    nn.init.zeros_(self.linears.bias.data)

    # foward pass
    def forward(self,x):
    if torch.is_tensor(x) != True:
    x = torch.from_numpy(x)
    a = x.float()
    for i in range(len(layers)-2):
    z = self.linears(a)
    a = self.activation(z)
    a = self.linears[-1](a)
    return a
    # Loss Functions
    #Loss PDE
    def lossPDE(self,x_PDE):
    g=x_PDE.clone()
    g.requires_grad=True #Enable differentiation
    f=self.forward(g)
    f_x=autograd.grad(f,g,torch.ones([x_PDE.shape[0],1]).to(device),\
    retain_graph=True, create_graph=True)[0]
    loss_PDE=self.loss_function(f_x,PDE(g))
    return loss_PDE

    Generate data


    # generate training and evaluation points
    x = torch.linspace(min,max,total_points).view(-1,1)
    y = torch.sin(x)
    print(x.shape, y.shape)

    # Set Boundary conditions:
    # Actually for this problem
    # we don't need extra boundary constraint
    # as it was concided with x_PDE point & value
    # BC_1=x[0,:]
    # BC_2=x[-1,:]
    # print(BC_1,BC_2)
    # x_BC=torch.vstack([BC_1,BC_2])
    # print(x_BC)
    x_PDE = x[1:-1,:]
    print(x_PDE.shape)

    x_PDE=x_PDE.float().to(device)
    # x_BC=x_BC.to(device)
    #Create Model
    layers = np.array([1,50,50,50,50,1])
    model = FCN(layers)
    print(model)
    model.to(device)
    params = list(model.parameters())
    optimizer = torch.optim.Adam(model.parameters(),lr=lr,amsgrad=False)

    Train Neural Network


    for i in range(500):
    yh = model(x_PDE)
    loss = model.loss_PDE(x_PDE) # use mean squared error
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
    if i%(500/10)==0:
    print(loss)

    predict the solution using PINN


    # predict the solution beyond training set
    x = torch.linspace(0,max+max,total_points).view(-1,1)
    yh=model(x.to(device))
    y=torch.sin(x)
    #Error
    print(model.lossBC(x.to(device)))

    y_plot=y.detach().numpy()
    yh_plot=yh.detach().cpu().numpy()
    fig, ax1 = plt.subplots()
    ax1.plot(x,y_plot,color='blue',label='Real')
    ax1.plot(x,yh_plot,color='red',label='Predicted')
    ax1.set_xlabel('x',color='black')
    ax1.set_ylabel('f(x)',color='black')
    ax1.tick_params(axis='y', color='black')
    ax1.legend(loc = 'upper left')


    [​IMG]

    But the end result was so disappointing. The model was unable to learn the simple ODE. I was wondering the model architecture of mine may have some issue which I couldn't figure out myself. Can anyone suggest any improvement?

    Continue reading...

Compartilhe esta Página