Tutorials v0.1 (#178)
Tutorial update and small fixes * Tutorials update + Tutorial FNO * Create a metric tracker callback * Update PINN for logging * Update plotter for plotting * Small fix LabelTensor * Small fix FNO --------- Co-authored-by: Dario Coscia <dariocoscia@cli-10-110-13-250.WIFIeduroamSTUD.units.it> Co-authored-by: Dario Coscia <dariocoscia@dhcp-176.eduroam.sissa.it>
This commit is contained in:
committed by
Nicola Demo
parent
939353f517
commit
a9b1bd2826
284
tutorials/tutorial3/tutorial.ipynb
vendored
284
tutorials/tutorial3/tutorial.ipynb
vendored
File diff suppressed because one or more lines are too long
116
tutorials/tutorial3/tutorial.py
vendored
116
tutorials/tutorial3/tutorial.py
vendored
@@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# # Tutorial 3: resolution of wave equation with custom Network
|
||||
# # Tutorial 3: resolution of wave equation with hard constraint PINNs.
|
||||
|
||||
# ### The problem solution
|
||||
|
||||
# In this tutorial we present how to solve the wave equation using the `SpatialProblem` and `TimeDependentProblem` class, and the `Network` class for building custom **torch** networks.
|
||||
# In this tutorial we present how to solve the wave equation using hard constraint PINNs. For doing so we will build a costum torch model and pass it to the `PINN` solver.
|
||||
#
|
||||
# The problem is written in the following form:
|
||||
#
|
||||
@@ -28,8 +28,12 @@ import torch
|
||||
|
||||
from pina.problem import SpatialProblem, TimeDependentProblem
|
||||
from pina.operators import laplacian, grad
|
||||
from pina.model import Network
|
||||
from pina import Condition, Span, PINN, Plotter
|
||||
from pina.geometry import CartesianDomain
|
||||
from pina.solvers import PINN
|
||||
from pina.trainer import Trainer
|
||||
from pina.equation import Equation
|
||||
from pina.equation.equation_factory import FixedValue
|
||||
from pina import Condition, Plotter
|
||||
|
||||
|
||||
# Now, the wave problem is written in PINA code as a class, inheriting from `SpatialProblem` and `TimeDependentProblem` since we deal with spatial, and time dependent variables. The equations are written as `conditions` that should be satisfied in the corresponding domains. `truth_solution` is the exact solution which will be compared with the predicted one.
|
||||
@@ -39,18 +43,14 @@ from pina import Condition, Span, PINN, Plotter
|
||||
|
||||
class Wave(TimeDependentProblem, SpatialProblem):
|
||||
output_variables = ['u']
|
||||
spatial_domain = Span({'x': [0, 1], 'y': [0, 1]})
|
||||
temporal_domain = Span({'t': [0, 1]})
|
||||
spatial_domain = CartesianDomain({'x': [0, 1], 'y': [0, 1]})
|
||||
temporal_domain = CartesianDomain({'t': [0, 1]})
|
||||
|
||||
def wave_equation(input_, output_):
|
||||
u_t = grad(output_, input_, components=['u'], d=['t'])
|
||||
u_tt = grad(u_t, input_, components=['dudt'], d=['t'])
|
||||
delta_u = laplacian(output_, input_, components=['u'], d=['x', 'y'])
|
||||
return delta_u - u_tt
|
||||
|
||||
def nil_dirichlet(input_, output_):
|
||||
value = 0.0
|
||||
return output_.extract(['u']) - value
|
||||
nabla_u = laplacian(output_, input_, components=['u'], d=['x', 'y'])
|
||||
return nabla_u - u_tt
|
||||
|
||||
def initial_condition(input_, output_):
|
||||
u_expected = (torch.sin(torch.pi*input_.extract(['x'])) *
|
||||
@@ -58,12 +58,12 @@ class Wave(TimeDependentProblem, SpatialProblem):
|
||||
return output_.extract(['u']) - u_expected
|
||||
|
||||
conditions = {
|
||||
'gamma1': Condition(location=Span({'x': [0, 1], 'y': 1, 't': [0, 1]}), function=nil_dirichlet),
|
||||
'gamma2': Condition(location=Span({'x': [0, 1], 'y': 0, 't': [0, 1]}), function=nil_dirichlet),
|
||||
'gamma3': Condition(location=Span({'x': 1, 'y': [0, 1], 't': [0, 1]}), function=nil_dirichlet),
|
||||
'gamma4': Condition(location=Span({'x': 0, 'y': [0, 1], 't': [0, 1]}), function=nil_dirichlet),
|
||||
't0': Condition(location=Span({'x': [0, 1], 'y': [0, 1], 't': 0}), function=initial_condition),
|
||||
'D': Condition(location=Span({'x': [0, 1], 'y': [0, 1], 't': [0, 1]}), function=wave_equation),
|
||||
'gamma1': Condition(location=CartesianDomain({'x': [0, 1], 'y': 1, 't': [0, 1]}), equation=FixedValue(0.)),
|
||||
'gamma2': Condition(location=CartesianDomain({'x': [0, 1], 'y': 0, 't': [0, 1]}), equation=FixedValue(0.)),
|
||||
'gamma3': Condition(location=CartesianDomain({'x': 1, 'y': [0, 1], 't': [0, 1]}), equation=FixedValue(0.)),
|
||||
'gamma4': Condition(location=CartesianDomain({'x': 0, 'y': [0, 1], 't': [0, 1]}), equation=FixedValue(0.)),
|
||||
't0': Condition(location=CartesianDomain({'x': [0, 1], 'y': [0, 1], 't': 0}), equation=Equation(initial_condition)),
|
||||
'D': Condition(location=CartesianDomain({'x': [0, 1], 'y': [0, 1], 't': [0, 1]}), equation=Equation(wave_equation)),
|
||||
}
|
||||
|
||||
def wave_sol(self, pts):
|
||||
@@ -76,78 +76,56 @@ class Wave(TimeDependentProblem, SpatialProblem):
|
||||
problem = Wave()
|
||||
|
||||
|
||||
# After the problem, a **torch** model is needed to solve the PINN. With the `Network` class the users can convert any **torch** model in a **PINA** model which uses label tensors with a single line of code. We will write a simple residual network using linear layers. Here we implement a simple residual network composed by linear torch layers.
|
||||
# After the problem, a **torch** model is needed to solve the PINN. Usually many models are already implemented in `PINA`, but the user has the possibility to build his/her own model in `pyTorch`. The hard constraint we impose are on the boundary of the spatial domain. Specificly our solution is written as:
|
||||
#
|
||||
# This neural network takes as input the coordinates (in this case $x$, $y$ and $t$) and provides the unkwown field of the Wave problem. The residual of the equations are evaluated at several sampling points (which the user can manipulate using the method `span_pts`) and the loss minimized by the neural network is the sum of the residuals.
|
||||
# $$ u_{\rm{pinn}} = xy(1-x)(1-y)\cdot NN(x, y, t), $$
|
||||
#
|
||||
# where $NN$ is the neural net output. This neural network takes as input the coordinates (in this case $x$, $y$ and $t$) and provides the unkwown field of the Wave problem. By construction it is zero on the boundaries. The residual of the equations are evaluated at several sampling points (which the user can manipulate using the method `discretise_domain`) and the loss minimized by the neural network is the sum of the residuals.
|
||||
|
||||
# In[3]:
|
||||
|
||||
|
||||
class TorchNet(torch.nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
class HardMLP(torch.nn.Module):
|
||||
|
||||
def __init__(self, input_dim, output_dim):
|
||||
super().__init__()
|
||||
|
||||
self.residual = torch.nn.Sequential(torch.nn.Linear(3, 24),
|
||||
torch.nn.Tanh(),
|
||||
torch.nn.Linear(24, 3))
|
||||
|
||||
self.layers = torch.nn.Sequential(torch.nn.Linear(input_dim, 20),
|
||||
torch.nn.Tanh(),
|
||||
torch.nn.Linear(20, 20),
|
||||
torch.nn.Tanh(),
|
||||
torch.nn.Linear(20, output_dim))
|
||||
|
||||
self.mlp = torch.nn.Sequential(torch.nn.Linear(3, 64),
|
||||
torch.nn.Tanh(),
|
||||
torch.nn.Linear(64, 1))
|
||||
# here in the foward we implement the hard constraints
|
||||
def forward(self, x):
|
||||
residual_x = self.residual(x)
|
||||
return self.mlp(x + residual_x)
|
||||
|
||||
# model definition
|
||||
model = Network(model = TorchNet(),
|
||||
input_variables=problem.input_variables,
|
||||
output_variables=problem.output_variables,
|
||||
extra_features=None)
|
||||
hard = x.extract(['x'])*(1-x.extract(['x']))*x.extract(['y'])*(1-x.extract(['y']))
|
||||
return hard*self.layers(x)
|
||||
|
||||
|
||||
# In this tutorial, the neural network is trained for 2000 epochs with a learning rate of 0.001. These parameters can be modified as desired.
|
||||
# We highlight that the generation of the sampling points and the train is here encapsulated within the function `generate_samples_and_train`, but only for saving some lines of code in the next cells; that function is not mandatory in the **PINA** framework. The training takes approximately one minute.
|
||||
# In this tutorial, the neural network is trained for 3000 epochs with a learning rate of 0.001 (default in `PINN`). Training takes approximately 1 minute.
|
||||
|
||||
# In[7]:
|
||||
|
||||
|
||||
def generate_samples_and_train(model, problem):
|
||||
# generate pinn object
|
||||
pinn = PINN(problem, model, lr=0.001)
|
||||
|
||||
pinn.span_pts(1000, 'random', locations=['D','t0', 'gamma1', 'gamma2', 'gamma3', 'gamma4'])
|
||||
pinn.train(1500, 150)
|
||||
return pinn
|
||||
pinn = PINN(problem, HardMLP(len(problem.input_variables), len(problem.output_variables)))
|
||||
problem.discretise_domain(1000, 'random', locations=['D','t0', 'gamma1', 'gamma2', 'gamma3', 'gamma4'])
|
||||
trainer = Trainer(pinn, max_epochs=3000)
|
||||
trainer.train()
|
||||
|
||||
|
||||
pinn = generate_samples_and_train(model, problem)
|
||||
# Notice that the loss on the boundaries of the spatial domain is exactly zero, as expected! After the training is completed one can now plot some results using the `Plotter` class of **PINA**.
|
||||
|
||||
|
||||
# After the training is completed one can now plot some results using the `Plotter` class of **PINA**.
|
||||
|
||||
# In[8]:
|
||||
# In[11]:
|
||||
|
||||
|
||||
plotter = Plotter()
|
||||
|
||||
# plotting at fixed time t = 0.6
|
||||
plotter.plot(pinn, fixed_variables={'t': 0.6})
|
||||
# plotting at fixed time t = 0.0
|
||||
plotter.plot(trainer, fixed_variables={'t': 0.0})
|
||||
|
||||
# plotting at fixed time t = 0.5
|
||||
plotter.plot(trainer, fixed_variables={'t': 0.5})
|
||||
|
||||
# We can also plot the pinn loss during the training to see the decrease.
|
||||
# plotting at fixed time t = 1.
|
||||
plotter.plot(trainer, fixed_variables={'t': 1.0})
|
||||
|
||||
# In[9]:
|
||||
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
plt.figure(figsize=(16, 6))
|
||||
plotter.plot_loss(pinn, label='Loss')
|
||||
|
||||
plt.grid()
|
||||
plt.legend()
|
||||
plt.show()
|
||||
|
||||
|
||||
# You can now trying improving the training by changing network, optimizer and its parameters, changin the sampling points,or adding extra features!
|
||||
|
||||
Reference in New Issue
Block a user