686 lines
97 KiB
Plaintext
Vendored
686 lines
97 KiB
Plaintext
Vendored
{
|
|
"cells": [
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "6f71ca5c",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Tutorial: Physics Informed Neural Networks on PINA\n",
|
|
"\n",
|
|
"[](https://colab.research.google.com/github/mathLab/PINA/blob/master/tutorials/tutorial1/tutorial.ipynb)\n"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "ef4949c9",
|
|
"metadata": {},
|
|
"source": [
|
|
"In this tutorial, we will demonstrate a typical use case of **PINA** on a toy problem, following the standard API procedure. \n",
|
|
"\n",
|
|
"<p align=\"center\">\n",
|
|
" <img src=\"../../readme/API_color.png\" alt=\"PINA API\" width=\"400\"/>\n",
|
|
"</p>\n",
|
|
"\n",
|
|
"Specifically, the tutorial aims to introduce the following topics:\n",
|
|
"\n",
|
|
"* Explaining how to build **PINA** Problems,\n",
|
|
"* Showing how to generate data for `PINN` training\n",
|
|
"\n",
|
|
"These are the two main steps needed **before** starting the modelling optimization (choose model and solver, and train). We will show each step in detail, and at the end, we will solve a simple Ordinary Differential Equation (ODE) problem using the `PINN` solver."
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "cf9c96e3",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Build a PINA problem"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "8a819659",
|
|
"metadata": {},
|
|
"source": [
|
|
"Problem definition in the **PINA** framework is done by building a python `class`, which inherits from one or more problem classes (`SpatialProblem`, `TimeDependentProblem`, `ParametricProblem`, ...) depending on the nature of the problem. Below is an example:\n",
|
|
"### Simple Ordinary Differential Equation\n",
|
|
"Consider the following:\n",
|
|
"\n",
|
|
"$$\n",
|
|
"\\begin{equation}\n",
|
|
"\\begin{cases}\n",
|
|
"\\frac{d}{dx}u(x) &= u(x) \\quad x\\in(0,1)\\\\\n",
|
|
"u(x=0) &= 1 \\\\\n",
|
|
"\\end{cases}\n",
|
|
"\\end{equation}\n",
|
|
"$$\n",
|
|
"\n",
|
|
"with the analytical solution $u(x) = e^x$. In this case, our ODE depends only on the spatial variable $x\\in(0,1)$ , meaning that our `Problem` class is going to be inherited from the `SpatialProblem` class:\n",
|
|
"\n",
|
|
"```python\n",
|
|
"from pina.problem import SpatialProblem\n",
|
|
"from pina.domain import CartesianProblem\n",
|
|
"\n",
|
|
"class SimpleODE(SpatialProblem):\n",
|
|
" \n",
|
|
" output_variables = ['u']\n",
|
|
" spatial_domain = CartesianProblem({'x': [0, 1]})\n",
|
|
"\n",
|
|
" # other stuff ...\n",
|
|
"```\n",
|
|
"\n",
|
|
"Notice that we define `output_variables` as a list of symbols, indicating the output variables of our equation (in this case only $u$), this is done because in **PINA** the `torch.Tensor`s are labelled, allowing the user maximal flexibility for the manipulation of the tensor. The `spatial_domain` variable indicates where the sample points are going to be sampled in the domain, in this case $x\\in[0,1]$.\n",
|
|
"\n",
|
|
"What if our equation is also time-dependent? In this case, our `class` will inherit from both `SpatialProblem` and `TimeDependentProblem`:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 1,
|
|
"id": "2373a925",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"## routine needed to run the notebook on Google Colab\n",
|
|
"try:\n",
|
|
" import google.colab\n",
|
|
" IN_COLAB = True\n",
|
|
"except:\n",
|
|
" IN_COLAB = False\n",
|
|
"if IN_COLAB:\n",
|
|
" !pip install \"pina-mathlab\"\n",
|
|
"\n",
|
|
"import warnings\n",
|
|
"\n",
|
|
"from pina.problem import SpatialProblem, TimeDependentProblem\n",
|
|
"from pina.domain import CartesianDomain\n",
|
|
"\n",
|
|
"warnings.filterwarnings('ignore')\n",
|
|
"\n",
|
|
"class TimeSpaceODE(SpatialProblem, TimeDependentProblem):\n",
|
|
" \n",
|
|
" output_variables = ['u']\n",
|
|
" spatial_domain = CartesianDomain({'x': [0, 1]})\n",
|
|
" temporal_domain = CartesianDomain({'t': [0, 1]})\n",
|
|
"\n",
|
|
" # other stuff ..."
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "ad8566b8",
|
|
"metadata": {},
|
|
"source": [
|
|
"where we have included the `temporal_domain` variable, indicating the time domain wanted for the solution.\n",
|
|
"\n",
|
|
"In summary, using **PINA**, we can initialize a problem with a class which inherits from different base classes: `SpatialProblem`, `TimeDependentProblem`, `ParametricProblem`, and so on depending on the type of problem we are considering. Here are some examples (more on the official documentation):\n",
|
|
"* ``SpatialProblem`` $\\rightarrow$ a differential equation with spatial variable(s) ``spatial_domain``\n",
|
|
"* ``TimeDependentProblem`` $\\rightarrow$ a time-dependent differential equation with temporal variable(s) ``temporal_domain``\n",
|
|
"* ``ParametricProblem`` $\\rightarrow$ a parametrized differential equation with parametric variable(s) ``parameter_domain``\n",
|
|
"* ``AbstractProblem`` $\\rightarrow$ any **PINA** problem inherits from here"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "592a4c43",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Write the problem class\n",
|
|
"\n",
|
|
"Once the `Problem` class is initialized, we need to represent the differential equation in **PINA**. In order to do this, we need to load the **PINA** operators from `pina.operator` module. Again, we'll consider Equation (1) and represent it in **PINA**:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 2,
|
|
"id": "f2608e2e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"import torch\n",
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"from pina.problem import SpatialProblem\n",
|
|
"from pina.operator import grad\n",
|
|
"from pina import Condition\n",
|
|
"from pina.domain import CartesianDomain\n",
|
|
"from pina.equation import Equation, FixedValue\n",
|
|
"\n",
|
|
"class SimpleODE(SpatialProblem):\n",
|
|
"\n",
|
|
" output_variables = ['u']\n",
|
|
" spatial_domain = CartesianDomain({'x': [0, 1]})\n",
|
|
"\n",
|
|
" domains ={\n",
|
|
" 'x0': CartesianDomain({'x': 0.}),\n",
|
|
" 'D': CartesianDomain({'x': [0, 1]})\n",
|
|
" }\n",
|
|
"\n",
|
|
" # defining the ode equation\n",
|
|
" def ode_equation(input_, output_):\n",
|
|
"\n",
|
|
" # computing the derivative\n",
|
|
" u_x = grad(output_, input_, components=['u'], d=['x'])\n",
|
|
"\n",
|
|
" # extracting the u input variable\n",
|
|
" u = output_.extract(['u'])\n",
|
|
"\n",
|
|
" # calculate the residual and return it\n",
|
|
" return u_x - u\n",
|
|
"\n",
|
|
" # conditions to hold\n",
|
|
" conditions = {\n",
|
|
" 'bound_cond': Condition(domain='x0', equation=FixedValue(1.)),\n",
|
|
" 'phys_cond': Condition(domain='D', equation=Equation(ode_equation))\n",
|
|
" }\n",
|
|
"\n",
|
|
" # defining the true solution\n",
|
|
" def truth_solution(self, pts):\n",
|
|
" return torch.exp(pts.extract(['x']))\n",
|
|
" \n",
|
|
"problem = SimpleODE()"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "7cf64d01",
|
|
"metadata": {},
|
|
"source": [
|
|
"After we define the `Problem` class, we need to write different class methods, where each method is a function returning a residual. These functions are the ones minimized during PINN optimization, given the initial conditions. For example, in the domain $[0,1]$, the ODE equation (`ode_equation`) must be satisfied. We represent this by returning the difference between subtracting the variable `u` from its gradient (the residual), which we hope to minimize to 0. This is done for all conditions. Notice that we do not pass directly a `python` function, but an `Equation` object, which is initialized with the `python` function. This is done so that all the computations and internal checks are done inside **PINA**.\n",
|
|
"\n",
|
|
"Once we have defined the function, we need to tell the neural network where these methods are to be applied. To do so, we use the `Condition` class. In the `Condition` class, we pass the location points and the equation we want minimized on those points (other possibilities are allowed, see the documentation for reference).\n",
|
|
"\n",
|
|
"Finally, it's possible to define a `truth_solution` function, which can be useful if we want to plot the results and see how the real solution compares to the expected (true) solution. Notice that the `truth_solution` function is a method of the `PINN` class, but it is not mandatory for problem definition.\n"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "78b30f95",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Generate data \n",
|
|
"\n",
|
|
"Data for training can come in form of direct numerical simulation results, or points in the domains. In case we perform unsupervised learning, we just need the collocation points for training, i.e. points where we want to evaluate the neural network. Sampling point in **PINA** is very easy, here we show three examples using the `.discretise_domain` method of the `AbstractProblem` class."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 3,
|
|
"id": "09ce5c3a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# sampling 20 points in [0, 1] through discretization in all locations\n",
|
|
"problem.discretise_domain(n=20, mode='grid', domains='all')\n",
|
|
"\n",
|
|
"# sampling 20 points in (0, 1) through latin hypercube sampling in D, and 1 point in x0\n",
|
|
"problem.discretise_domain(n=20, mode='latin', domains=['D'])\n",
|
|
"problem.discretise_domain(n=1, mode='random', domains=['x0'])\n",
|
|
"\n",
|
|
"# sampling 20 points in (0, 1) randomly\n",
|
|
"problem.discretise_domain(n=20, mode='random')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8fbb679f",
|
|
"metadata": {},
|
|
"source": [
|
|
"We are going to use latin hypercube points for sampling. We need to sample in all the conditions domains. In our case we sample in `D` and `x0`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 4,
|
|
"id": "329962b6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# sampling for training\n",
|
|
"problem.discretise_domain(1, 'random', domains=['x0']) # TODO check\n",
|
|
"problem.discretise_domain(20, 'lh', domains=['D'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ca2ac5c2",
|
|
"metadata": {},
|
|
"source": [
|
|
"The points are saved in a python `dict`, and can be accessed by calling the attribute `input_pts` of the problem "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 5,
|
|
"id": "d6ed9aaf",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Input points: {'x0': LabelTensor([[0.]]), 'D': LabelTensor([[0.6732],\n",
|
|
" [0.9077],\n",
|
|
" [0.7904],\n",
|
|
" [0.1018],\n",
|
|
" [0.4341],\n",
|
|
" [0.3175],\n",
|
|
" [0.7237],\n",
|
|
" [0.8685],\n",
|
|
" [0.0957],\n",
|
|
" [0.1807],\n",
|
|
" [0.2316],\n",
|
|
" [0.0491],\n",
|
|
" [0.9556],\n",
|
|
" [0.2708],\n",
|
|
" [0.4589],\n",
|
|
" [0.5172],\n",
|
|
" [0.3763],\n",
|
|
" [0.8106],\n",
|
|
" [0.6397],\n",
|
|
" [0.5970]])}\n",
|
|
"Input points labels: ['x']\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"print('Input points:', problem.discretised_domains)\n",
|
|
"print('Input points labels:', problem.discretised_domains['D'].labels)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "669e8534",
|
|
"metadata": {},
|
|
"source": [
|
|
"To visualize the sampled points we can use `matplotlib.pyplot`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 6,
|
|
"id": "3802e22a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAkEAAAGdCAYAAAAVEKdkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAIcJJREFUeJzt3XtwVOXBx/HfJiEbVHYjtyzRRQpVQUEZgwlBHVrJNBZHZcQRkSLSVGoF6ksQ5SZptRrqFRWU0dZSRygUi1QwE4vBO1Ewgcq9WpAguAGK7CKXJCTP+wdlNTVgNtmzIft8PzM7DCfPOec5z7Lud0420WWMMQIAALBMQktPAAAAoCUQQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACslNTSE2gJdXV12r17t9q1ayeXy9XS0wEAAI1gjNHBgweVnp6uhITm38exMoJ2794tv9/f0tMAAABNsHPnTp177rnNPo6VEdSuXTtJxxfR4/G08GwAAEBjhEIh+f3+8Pt4c1kZQSe+BebxeIggAABamWh9lIUPRgMAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwUkwiaM6cOerWrZtSUlKUlZWl1atXn3L84sWL1bNnT6WkpKhPnz4qKio66dg777xTLpdLs2bNivKsAQBAPHM8ghYtWqT8/HwVFBSovLxcl156qXJzc7Vnz54Gx69atUrDhw9XXl6e1q5dqyFDhmjIkCHasGHDd8a++uqr+vDDD5Wenu70ZQAAgDjjeAQ98cQTuuOOOzR69GhddNFFmjt3rs444wy9+OKLDY5/6qmndM0112jSpEnq1auXHnzwQV122WWaPXt2vXG7du3S+PHjNX/+fLVp08bpywAAAHHG0Qiqrq5WWVmZcnJyvjlhQoJycnJUWlra4D6lpaX1xktSbm5uvfF1dXUaOXKkJk2apIsvvvh751FVVaVQKFTvAQAA7OZoBO3bt0+1tbVKS0urtz0tLU2BQKDBfQKBwPeO//3vf6+kpCT9+te/btQ8CgsL5fV6ww+/3x/hlQAAgHjT6n46rKysTE899ZTmzZsnl8vVqH2mTJmiYDAYfuzcudPhWQIAgNOdoxHUsWNHJSYmqrKyst72yspK+Xy+Bvfx+XynHP/ee+9pz5496tq1q5KSkpSUlKQdO3Zo4sSJ6tatW4PHdLvd8ng89R4AAMBujkZQcnKyMjIyVFJSEt5WV1enkpISZWdnN7hPdnZ2vfGStGLFivD4kSNH6pNPPtG6devCj/T0dE2aNElvvPGGcxcDAADiSpLTJ8jPz9eoUaPUr18/ZWZmatasWTp06JBGjx4tSbrtttt0zjnnqLCwUJJ09913a+DAgXr88cd17bXXauHChfr444/1/PPPS5I6dOigDh061DtHmzZt5PP5dOGFFzp9OQAAIE44HkHDhg3T3r17NWPGDAUCAfXt21fFxcXhDz9XVFQoIeGbG1IDBgzQggULNH36dE2dOlXnn3++li5dqt69ezs9VQAAYBGXMca09CRiLRQKyev1KhgM8vkgAABaiWi/f7e6nw4DAACIBiIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJViEkFz5sxRt27dlJKSoqysLK1evfqU4xcvXqyePXsqJSVFffr0UVFRUfhrNTU1uu+++9SnTx+deeaZSk9P12233abdu3c7fRkAACCOOB5BixYtUn5+vgoKClReXq5LL71Uubm52rNnT4PjV61apeHDhysvL09r167VkCFDNGTIEG3YsEGSdPjwYZWXl+v+++9XeXm5lixZoq1bt+r66693+lIAAEAccRljjJMnyMrK0uWXX67Zs2dLkurq6uT3+zV+/HhNnjz5O+OHDRumQ4cOafny5eFt/fv3V9++fTV37twGz7FmzRplZmZqx44d6tq16/fOKRQKyev1KhgMyuPxNPHKAABALEX7/dvRO0HV1dUqKytTTk7ONydMSFBOTo5KS0sb3Ke0tLTeeEnKzc096XhJCgaDcrlcSk1NbfDrVVVVCoVC9R4AAMBujkbQvn37VFtbq7S0tHrb09LSFAgEGtwnEAhENP7o0aO67777NHz48JNWYWFhobxeb/jh9/ubcDUAACCetOqfDqupqdHNN98sY4yee+65k46bMmWKgsFg+LFz584YzhIAAJyOkpw8eMeOHZWYmKjKysp62ysrK+Xz+Rrcx+fzNWr8iQDasWOHVq5cecrvDbrdbrnd7iZeBQAAiEeO3glKTk5WRkaGSkpKwtvq6upUUlKi7OzsBvfJzs6uN16SVqxYUW/8iQD69NNP9eabb6pDhw7OXAAAAIhbjt4JkqT8/HyNGjVK/fr1U2ZmpmbNmqVDhw5p9OjRkqTbbrtN55xzjgoLCyVJd999twYOHKjHH39c1157rRYuXKiPP/5Yzz//vKTjAXTTTTepvLxcy5cvV21tbfjzQu3bt1dycrLTlwQAAOKA4xE0bNgw7d27VzNmzFAgEFDfvn1VXFwc/vBzRUWFEhK+uSE1YMAALViwQNOnT9fUqVN1/vnna+nSperdu7ckadeuXXrttdckSX379q13rrfeeks/+tGPnL4kAAAQBxz/PUGnI35PEAAArU+r+j1BAAAApysiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCAACAlYggAABgJSIIAABYiQgCAABWIoIAAICViCAAAGAlIggAAFiJCAIAAFYiggAAgJWIIAAAYCUiCAAA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AgAALBdRBDVWr169dM011+iOO+7Q3LlzVVNTo3HjxumWW24J/2TYrl27NGjQIL300kvKzMyU1+tVXl6e8vPz1b59e3k8Ho0fP17Z2dnhnwz739DZt29f+HyR/HQYAACAIxEkSfPnz9e4ceM0aNAgJSQkaOjQoXr66afDX6+pqdHWrVt1+PDh8LYnn3wyPLaqqkq5ubl69tlnnZoiAACwmCO/J+h0x+8JAgCg9WkVvycIAADgdEcEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsBIRBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArJbX0BFqCMUaSFAqFWngmAACgsU68b594H28uKyPo4MGDkiS/39/CMwEAAJE6ePCgvF5vs4/jMtHKqVakrq5Ou3fvVrt27eRyuaJ67FAoJL/fr507d8rj8UT12Dg51r1lsO4th7VvGax7yzix7hUVFXK5XEpPT1dCQvM/0WPlnaCEhASde+65jp7D4/HwAmkBrHvLYN1bDmvfMlj3luH1eqO67nwwGgAAWIkIAgAAViKCosztdqugoEBut7ulp2IV1r1lsO4th7VvGax7y3Bq3a38YDQAAAB3ggAAgJWIIAAAYCUiCAAAWIkIAgAAViKCIjRnzhx169ZNKSkpysrK0urVq085fvHixerZs6dSUlLUp08fFRUVxWim8SeStX/hhRd01VVX6eyzz9bZZ5+tnJyc732u0LBI/82fsHDhQrlcLg0ZMsTZCcaxSNf+wIEDGjt2rLp06SK3260LLriA/+Y0QaTrPmvWLF144YVq27at/H6/JkyYoKNHj8ZotvHh3Xff1XXXXaf09HS5XC4tXbr0e/d5++23ddlll8ntduuHP/yh5s2bF/mJDRpt4cKFJjk52bz44otm48aN5o477jCpqammsrKywfEffPCBSUxMNI888ojZtGmTmT59umnTpo1Zv359jGfe+kW69rfeequZM2eOWbt2rdm8ebO5/fbbjdfrNV988UWMZ966RbruJ2zfvt2cc8455qqrrjI33HBDbCYbZyJd+6qqKtOvXz8zePBg8/7775vt27ebt99+26xbty7GM2/dIl33+fPnG7fbbebPn2+2b99u3njjDdOlSxczYcKEGM+8dSsqKjLTpk0zS5YsMZLMq6++esrx27ZtM2eccYbJz883mzZtMs8884xJTEw0xcXFEZ2XCIpAZmamGTt2bPjvtbW1Jj093RQWFjY4/uabbzbXXnttvW1ZWVnml7/8paPzjEeRrv3/OnbsmGnXrp3585//7NQU41JT1v3YsWNmwIAB5g9/+IMZNWoUEdREka79c889Z7p3726qq6tjNcW4FOm6jx071lx99dX1tuXn55srrrjC0XnGs8ZE0L333msuvvjietuGDRtmcnNzIzoX3w5rpOrqapWVlSknJye8LSEhQTk5OSotLW1wn9LS0nrjJSk3N/ek49Gwpqz9/zp8+LBqamrUvn17p6YZd5q67g888IA6d+6svLy8WEwzLjVl7V977TVlZ2dr7NixSktLU+/evfXwww+rtrY2VtNu9Zqy7gMGDFBZWVn4W2bbtm1TUVGRBg8eHJM52ypa769W/g9Um2Lfvn2qra1VWlpave1paWnasmVLg/sEAoEGxwcCAcfmGY+asvb/67777lN6evp3XjQ4uaas+/vvv68//vGPWrduXQxmGL+asvbbtm3TypUrNWLECBUVFemzzz7TXXfdpZqaGhUUFMRi2q1eU9b91ltv1b59+3TllVfKGKNjx47pzjvv1NSpU2MxZWud7P01FArpyJEjatu2baOOw50gxL2ZM2dq4cKFevXVV5WSktLS04lbBw8e1MiRI/XCCy+oY8eOLT0d69TV1alz5856/vnnlZGRoWHDhmnatGmaO3duS08trr399tt6+OGH9eyzz6q8vFxLlizR66+/rgcffLClp4ZG4E5QI3Xs2FGJiYmqrKyst72yslI+n6/BfXw+X0Tj0bCmrP0Jjz32mGbOnKk333xTl1xyiZPTjDuRrvu///1vff7557ruuuvC2+rq6iRJSUlJ2rp1q3r06OHspONEU/7Nd+nSRW3atFFiYmJ4W69evRQIBFRdXa3k5GRH5xwPmrLu999/v0aOHKlf/OIXkqQ+ffro0KFDGjNmjKZNm6aEBO41OOFk768ej6fRd4Ek7gQ1WnJysjIyMlRSUhLeVldXp5KSEmVnZze4T3Z2dr3xkrRixYqTjkfDmrL2kvTII4/owQcfVHFxsfr16xeLqcaVSNe9Z8+eWr9+vdatWxd+XH/99frxj3+sdevWye/3x3L6rVpT/s1fccUV+uyzz8LhKUn/+te/1KVLFwKokZqy7ocPH/5O6JwIUcP/mtMxUXt/jewz23ZbuHChcbvdZt68eWbTpk1mzJgxJjU11QQCAWOMMSNHjjSTJ08Oj//ggw9MUlKSeeyxx8zmzZtNQUEBPyLfRJGu/cyZM01ycrJ55ZVXzJdffhl+HDx4sKUuoVWKdN3/Fz8d1nSRrn1FRYVp166dGTdunNm6datZvny56dy5s/nd737XUpfQKkW67gUFBaZdu3bmL3/5i9m2bZv5xz/+YXr06GFuvvnmlrqEVungwYNm7dq1Zu3atUaSeeKJJ8zatWvNjh07jDHGTJ482YwcOTI8/sSPyE+aNMls3rzZzJkzhx+Rj4VnnnnGdO3a1SQnJ5vMzEzz4Ycfhr82cOBAM2rUqHrj//rXv5oLLrjAJCcnm4svvti8/vrrMZ5x/Ihk7c877zwj6TuPgoKC2E+8lYv03/y3EUHNE+nar1q1ymRlZRm32226d+9uHnroIXPs2LEYz7r1i2Tda2pqzG9+8xvTo0cPk5KSYvx+v7nrrrvMV199FfuJt2JvvfVWg//NPrHWo0aNMgMHDvzOPn379jXJycmme/fu5k9/+lPE53UZw/06AABgHz4TBAAArEQEAQAAKxFBAADASkQQAACwEhEEAACsRAQBAAArEUEAAMBKRBAAALASEQQAAKxEBAEAACsRQQAAwEpEEAAAsNL/A+b5qtyBscDXAAAAAElFTkSuQmCC",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"variables=problem.spatial_variables\n",
|
|
"fig = plt.figure()\n",
|
|
"proj = \"3d\" if len(variables) == 3 else None\n",
|
|
"ax = fig.add_subplot(projection=proj)\n",
|
|
"for location in problem.input_pts:\n",
|
|
" coords = problem.input_pts[location].extract(variables).T.detach()\n",
|
|
" ax.plot(coords.flatten(),torch.zeros(coords.flatten().shape),\".\",label=location)\n"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "22e502dd",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Perform a small training"
|
|
]
|
|
},
|
|
{
|
|
"attachments": {},
|
|
"cell_type": "markdown",
|
|
"id": "075f43f5",
|
|
"metadata": {},
|
|
"source": [
|
|
"Once we have defined the problem and generated the data we can start the modelling. Here we will choose a `FeedForward` neural network available in `pina.model`, and we will train using the `PINN` solver from `pina.solver`. We highlight that this training is fairly simple, for more advanced stuff consider the tutorials in the ***Physics Informed Neural Networks*** section of ***Tutorials***. For training we use the `Trainer` class from `pina.trainer`. Here we show a very short training and some method for plotting the results. Notice that by default all relevant metrics (e.g. MSE error during training) are going to be tracked using a `lightning` logger, by default `CSVLogger`. If you want to track the metric by yourself without a logger, use `pina.callback.MetricTracker`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 7,
|
|
"id": "3bb4dc9b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"GPU available: False, used: False\n",
|
|
"TPU available: False, using: 0 TPU cores\n",
|
|
"HPU available: False, using: 0 HPUs\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Epoch 1499: 100%|██████████| 1/1 [00:00<00:00, 87.10it/s, v_num=0, bound_cond_loss=1.61e-9, phys_cond_loss=5.27e-6, train_loss=5.27e-6] "
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"`Trainer.fit` stopped: `max_epochs=1500` reached.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Epoch 1499: 100%|██████████| 1/1 [00:00<00:00, 58.01it/s, v_num=0, bound_cond_loss=1.61e-9, phys_cond_loss=5.27e-6, train_loss=5.27e-6]\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"from pina import Trainer\n",
|
|
"from pina.solver import PINN\n",
|
|
"from pina.model import FeedForward\n",
|
|
"from lightning.pytorch.loggers import TensorBoardLogger\n",
|
|
"from pina.optim import TorchOptimizer\n",
|
|
"\n",
|
|
"\n",
|
|
"# build the model\n",
|
|
"model = FeedForward(\n",
|
|
" layers=[10, 10],\n",
|
|
" func=torch.nn.Tanh,\n",
|
|
" output_dimensions=len(problem.output_variables),\n",
|
|
" input_dimensions=len(problem.input_variables)\n",
|
|
")\n",
|
|
"\n",
|
|
"# create the PINN object\n",
|
|
"pinn = PINN(problem, model, TorchOptimizer(torch.optim.Adam, lr=0.005))\n",
|
|
"\n",
|
|
"# create the trainer\n",
|
|
"trainer = Trainer(solver=pinn, max_epochs=1500, logger=TensorBoardLogger('tutorial_logs'), \n",
|
|
" accelerator='cpu',\n",
|
|
" train_size=1.0,\n",
|
|
" test_size=0.0,\n",
|
|
" val_size=0.0,\n",
|
|
" enable_model_summary=False) # we train on CPU and avoid model summary at beginning of training (optional)\n",
|
|
"\n",
|
|
"# train\n",
|
|
"trainer.train()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f8b4f496",
|
|
"metadata": {},
|
|
"source": [
|
|
"After the training we can inspect trainer logged metrics (by default **PINA** logs mean square error residual loss). The logged metrics can be accessed online using one of the `Lightning` loggers. The final loss can be accessed by `trainer.logged_metrics`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 8,
|
|
"id": "f5fbf362",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'bound_cond_loss': tensor(1.6091e-09),\n",
|
|
" 'phys_cond_loss': tensor(5.2722e-06),\n",
|
|
" 'train_loss': tensor(5.2738e-06)}"
|
|
]
|
|
},
|
|
"execution_count": 8,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"# inspecting final loss\n",
|
|
"trainer.logged_metrics"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "0963d7d2",
|
|
"metadata": {},
|
|
"source": [
|
|
"By using `matplotlib` we can also do some qualitative plots of the solution. "
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 9,
|
|
"id": "ffbf0d5e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"<matplotlib.legend.Legend at 0x7f445d8f7260>"
|
|
]
|
|
},
|
|
"execution_count": 9,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAqgAAAKTCAYAAADVBfoyAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAclZJREFUeJzt3Xd0FHXDxfE72XRIIUBIAqGE3ksoho6CgIpgo6gURWwgIiKKDdsjdlFBUFpQpFkARUQBCUivofdeEnoqpO68f/CQ94mEkpBkNsn3c86e487+ZvYOQ/BmqmGapikAAADAQThZHQAAAAD4XxRUAAAAOBQKKgAAABwKBRUAAAAOhYIKAAAAh0JBBQAAgEOhoAIAAMChOFsdIDfY7XadPHlSXl5eMgzD6jgAAAD4F9M0FR8fr6CgIDk5XX8faaEoqCdPnlRwcLDVMQAAAHADx44dU7ly5a47plAUVC8vL0mXV9jb29viNAAAAPi3uLg4BQcHZ/S26ykUBfXKYX1vb28KKgAAgAO7mdMxuUgKAAAADoWCCgAAAIdCQQUAAIBDKRTnoN6s9PR0paamWh0DKFRcXFxks9msjgEAKESKREE1TVPR0dGKiYmxOgpQKPn6+iogIID7EAMAckWRKKhXyqm/v788PT35nyiQS0zT1MWLF3X69GlJUmBgoMWJAACFQaEvqOnp6RnltGTJklbHAQodDw8PSdLp06fl7+/P4X4AwC0r9BdJXTnn1NPT0+IkQOF15eeLc7wBALmh0BfUKzisD+Qdfr4AALmpyBRUAAAAFAwUVAAAADiUbBXUUaNGqUmTJvLy8pK/v7+6deumPXv2XHeetm3byjCMq1533313xph+/fpd9XmnTp1ytkbId23bttWQIUOsjpHn3nrrLTVo0CDfvi88PFy+vr63vJyIiAgZhsFt1gAABUa2CuqyZcs0cOBArVmzRosWLVJqaqruvPNOJSYmXnOeX375RVFRURmv7du3y2az6aGHHso0rlOnTpnGzZgxI2drVIhcKe4ffPBBpulz584tUOf8hYeHZ/lLR0xMjAzDUERExE0vq1+/furWrVvuBixEsvploXnz5oqKipKPj481oQAAyKZs3WZq4cKFmd6Hh4fL399fGzduVOvWrbOcx8/PL9P7mTNnytPT86qC6ubmpoCAgOzEKRLc3d314Ycf6qmnnlKJEiXy9btTU1Pl4uKSK8tydnbW4sWLtXTpUrVr1y5XlplfTNNUenq61TFyzNXVlZ8tAECBckvnoMbGxkq6uoRez6RJk9SzZ08VK1Ys0/SIiAj5+/urevXqeuaZZ3Tu3LlrLiM5OVlxcXGZXtlhmqYupqRZ8jJNM1tZ27dvr4CAAI0aNeq641asWKFWrVrJw8NDwcHBGjx4cKY924ZhaO7cuZnm8fX1VXh4uCTp8OHDMgxDs2bNUps2beTu7q4ffvhB586dU69evVS2bFl5enqqbt26Odq7XaxYMT3++ON65ZVXrjvu2LFj6t69u3x9feXn56euXbvq8OHDki4fYp86darmzZuXcSpIRESEHnzwQQ0aNChjGUOGDJFhGNq9e7ckKSUlRcWKFdPixYslXf77M3jwYPn7+8vd3V0tW7bU+vXrM+a/ckj8jz/+UGhoqNzc3LRixYqrsh44cEAhISEaNGhQltvVNE299dZbKl++vNzc3BQUFKTBgwdnfH7hwgX16dNHJUqUkKenpzp37qx9+/Zd888mq73HQ4YMUdu2bTM+X7Zsmb744ouMP5/Dhw9neYj/559/Vu3ateXm5qaKFSvq008/zbTcihUr6v3339fjjz8uLy8vlS9fXt9+++01swEAkJtyfKN+u92uIUOGqEWLFqpTp85NzbNu3Tpt375dkyZNyjS9U6dOuv/++1WpUiUdOHBAr776qjp37qzVq1dnedPvUaNG6e23385pdF1KTVetN//M8fy3Yuc7HeXpevN/7DabTe+//74efvhhDR48WOXKlbtqzIEDB9SpUye99957mjx5ss6cOaNBgwZp0KBBmjJlSrbyvfLKK/r000/VsGFDubu7KykpSaGhoXr55Zfl7e2t33//Xb1791blypXVtGnTbC37rbfeUpUqVfTTTz/pwQcfvOrz1NRUdezYUWFhYfrnn3/k7Oys9957T506ddLWrVs1bNgw7dq1S3FxcRnr5efnp23btumbb77JWM6yZctUqlQpRUREqEaNGlq/fr1SU1PVvHlzSdLw4cP1888/a+rUqapQoYI++ugjdezYUfv378/0y9Yrr7yiTz75RCEhISpRokSmUxG2bt2qjh07qn///nrvvfeyXN+ff/5Zn3/+uWbOnKnatWsrOjpaW7Zsyfi8X79+2rdvn3799Vd5e3vr5Zdf1l133aWdO3fmaM/1F198ob1796pOnTp65513JEmlS5fOKPhXbNy4Ud27d9dbb72lHj16aNWqVXr22WdVsmRJ9evXL2Pcp59+qnfffVevvvqqfvrpJz3zzDNq06aNqlevnu1sAABkR473oA4cOFDbt2/XzJkzb3qeSZMmqW7dulcVm549e+ree+9V3bp11a1bN82fP1/r16+/5rmJI0aMUGxsbMbr2LFjOV2NAuG+++5TgwYNNHLkyCw/HzVqlB555BENGTJEVatWVfPmzfXll1/qu+++U1JSUra+a8iQIRm/LAQGBqps2bIaNmyYGjRooJCQED333HPq1KmTZs+ene31CAoK0vPPP6/XXntNaWlpV30+a9Ys2e12TZw4UXXr1lXNmjU1ZcoUHT16VBERESpevLg8PDwyTgcJCAiQq6ur2rZtq507d+rMmTO6cOGCdu7cqeeffz7j709ERISaNGkiT09PJSYmaty4cfr444/VuXNn1apVSxMmTJCHh8dVvzi988476tChgypXrpypuK5atUpt27bVsGHDrllOJeno0aMKCAhQ+/btVb58eTVt2lQDBgyQpIxiOnHiRLVq1Ur169fXDz/8oBMnTly1p/tm+fj4yNXVVZ6enhl/Pln9gvfZZ5/pjjvu0BtvvKFq1aqpX79+GjRokD7++ONM4+666y49++yzqlKlil5++WWVKlVKS5cuzVE2AACyI0d7UAcNGqT58+dr+fLlWe7Ry0piYqJmzpyZsWfnekJCQlSqVCnt379fd9xxx1Wfu7m5yc3NLdu5r/BwsWnnOx1zPP+t8HDJ2WMgP/zwQ91+++0aNmzYVZ9t2bJFW7du1Q8//JAxzTRN2e12HTp0SDVr1rzp72ncuHGm9+np6Xr//fc1e/ZsnThxQikpKUpOTs7xk7lefvllffPNN5o8ebK6d+9+1Xrs379fXl5emaYnJSXpwIED11xmnTp15Ofnp2XLlsnV1VUNGzbUPffco7Fjx0q6vEf1ymHwAwcOKDU1VS1atMiY38XFRU2bNtWuXbsyLffffxbS5dLZoUMH/ec//7nhnQseeughjR49WiEhIerUqZPuuusudenSRc7Oztq1a5ecnZ3VrFmzjPElS5ZU9erVr8qR23bt2qWuXbtmmtaiRQuNHj1a6enpGaW2Xr16GZ8bhqGAgACdPn06T7MBACBls6CapqnnnntOc+bMUUREhCpVqnTT8/74449KTk7Wo48+esOxx48f17lz5xQYGJideDfNMIxsHWZ3BK1bt1bHjh01YsSITIdhJSkhIUFPPfVUpvMbryhfvryky+v87/Mks3os5b/PDf7444/1xRdfaPTo0apbt66KFSumIUOGKCUlJUfr4evrqxEjRujtt9/WPffcc9V6hIaGZiraV5QuXfqayzQMQ61bt1ZERITc3NzUtm1b1atXT8nJydq+fbtWrVqVZbG/kX//WVzJERQUpBkzZujxxx+Xt7f3NecPDg7Wnj17tHjxYi1atEjPPvusPv74Yy1btizbWSTJycnpprZhbvn3aQaGYchut+fZ9wEAcEW2DvEPHDhQ06ZN0/Tp0+Xl5aXo6GhFR0fr0qVLGWP69OmjESNGXDXvpEmT1K1bN5UsWTLT9ISEBL300ktas2aNDh8+rCVLlqhr166qUqWKOna0Zi+no/rggw/022+/afXq1ZmmN2rUSDt37lSVKlWuerm6ukq6XKyioqIy5tm3b58uXrx4w+9cuXKlunbtqkcffVT169dXSEiI9u7de0vr8dxzz8nJyUlffPHFVeuxb98++fv7X7UeV26R5OrqmuUV9W3atFFERIQiIiLUtm1bOTk5qXXr1vr444+VnJycsce0cuXKcnV11cqVKzPmTU1N1fr161WrVq0bZvfw8ND8+fPl7u6ujh07Kj4+/obju3Tpoi+//FIRERFavXq1tm3bppo1ayotLU1r167NGHvu3Dnt2bPnmjn+vQ0lKTIyMtP7a/35/K+aNWtmWn/p8nauVq1alqcEAACQ37JVUMeNG6fY2Fi1bdtWgYGBGa9Zs2ZljDl69OhV/xPds2ePVqxYof79+1+1TJvNpq1bt+ree+9VtWrV1L9/f4WGhuqff/65pcP4hVHdunX1yCOP6Msvv8w0/eWXX9aqVas0aNAgRUZGat++fZo3b16mK9tvv/12jRkzRps3b9aGDRv09NNP39SFOFWrVtWiRYu0atUq7dq1S0899ZROnTp1S+vh7u6ut99++6r1eOSRR1SqVCl17dpV//zzjw4dOqSIiAgNHjxYx48fl3T56vKtW7dqz549Onv2bMYexCvnoe7YsUMtW7bMmPbDDz+ocePGGXtDixUrpmeeeUYvvfSSFi5cqJ07d2rAgAG6ePFiln8/s1KsWDH9/vvvcnZ2VufOnZWQkJDluPDwcE2aNEnbt2/XwYMHNW3aNHl4eKhChQqqWrWqunbtqgEDBmjFihXasmWLHn30UZUtW/aqw+9X3H777dqwYYO+++477du3TyNHjtT27dszjalYsaLWrl2rw4cP6+zZs1nu8XzxxRe1ZMkSvfvuu9q7d6+mTp2qMWPG5GgvMwAAeSFbBdU0zSxf/3vIOSIiIuPWRVdUr15dpmmqQ4cOVy3Tw8NDf/75p06fPq2UlBQdPnxY3377rcqUKZOjFSrs3nnnnatKR7169bRs2TLt3btXrVq1UsOGDfXmm28qKCgoY8ynn36q4OBgtWrVSg8//LCGDRt2U+eRvv7662rUqJE6duyotm3bKiAgIFdulN+3b1+FhIRkmubp6anly5erfPnyuv/++1WzZk31799fSUlJGYfSBwwYoOrVq6tx48YqXbp0xp7AunXrytfXVw0aNFDx4sUlXS6o6enpGeefXvHBBx/ogQceUO/evdWoUSPt379ff/75Z7buM1u8eHH98ccfMk1Td999d5YPq/D19dWECRPUokUL1atXT4sXL9Zvv/2WcRRhypQpCg0N1T333KOwsDCZpqkFCxZc8xeHjh076o033tDw4cPVpEkTxcfHq0+fPpnGDBs2TDabTbVq1VLp0qV19OjRq5bTqFEjzZ49WzNnzlSdOnX05ptv6p133rnq1BEAAKximNm9MacDiouLk4+Pj2JjY686JzApKUmHDh1SpUqV5O7ublFCoHDj5wwAcCPX62v/dks36gcAAEDBZE9LlT01Zxc95zUKKgAAQBG06cdROvJhMx3bscrqKFehoAIAABQx0Ud2q/bur1Qp7aCO7lhjdZyrUFABAACKENNu17kZz8jDSNE2l/q67YEhVke6CgUVAACgCNn829eqnbRJSaaLvLuPkc3meHXQ8RIBAAAgT5w/dUyVN78vSdpY6WlVqFrvBnNYg4IKAABQRBye9px8lKj9thA1efhNq+NcEwUVAACgCNiyeIYaxS9Vmukks8uXGY9Dd0QUVOSpiIgIGYahmJiYW1rO4cOHZRjGVc+eBwAANxYfe14BK16TJK0P7KWqDVpZnOj6KKgOyjCM677eeustqyPmmX79+l31ONXg4GBFRUWpTp061oQCAKAA2/H9iyqjczpuBKhB7w+tjnNDzlYHQNaioqIy/nvWrFl68803tWfP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",
|
|
"text/plain": [
|
|
"<Figure size 800x800 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"pts = pinn.problem.spatial_domain.sample(256, 'grid', variables='x')\n",
|
|
"predicted_output = pinn.forward(pts).extract('u').as_subclass(torch.Tensor).cpu().detach()\n",
|
|
"true_output = pinn.problem.truth_solution(pts).cpu().detach()\n",
|
|
"pts = pts.cpu()\n",
|
|
"fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8, 8))\n",
|
|
"ax.plot(pts.extract(['x']), predicted_output, label='Neural Network solution')\n",
|
|
"ax.plot(pts.extract(['x']), true_output, label='True solution')\n",
|
|
"plt.legend()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "bf47b98a",
|
|
"metadata": {},
|
|
"source": [
|
|
"The solution is overlapped with the actual one, and they are barely indistinguishable. We can also take a look at the loss using `TensorBoard`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "fcac93e4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"Reusing TensorBoard on port 6006 (pid 39131), started 2:16:30 ago. (Use '!kill 39131' to kill it.)"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"\n",
|
|
" <iframe id=\"tensorboard-frame-d501808aeaa2cb8c\" width=\"100%\" height=\"800\" frameborder=\"0\">\n",
|
|
" </iframe>\n",
|
|
" <script>\n",
|
|
" (function() {\n",
|
|
" const frame = document.getElementById(\"tensorboard-frame-d501808aeaa2cb8c\");\n",
|
|
" const url = new URL(\"http://localhost\");\n",
|
|
" const port = 6006;\n",
|
|
" if (port) {\n",
|
|
" url.port = port;\n",
|
|
" }\n",
|
|
" frame.src = url;\n",
|
|
" })();\n",
|
|
" </script>\n",
|
|
" "
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"print('\\nTo load TensorBoard run load_ext tensorboard on your terminal')\n",
|
|
"print(\"To visualize the loss you can run tensorboard --logdir 'tutorial_logs' on your terminal\\n\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "58172899",
|
|
"metadata": {},
|
|
"source": [
|
|
"As we can see the loss has not reached a minimum, suggesting that we could train for longer! Alternatively, we can also take look at the loss using callbacks. Here we use `MetricTracker` from `pina.callback`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 11,
|
|
"id": "03398692",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"GPU available: False, used: False\n",
|
|
"TPU available: False, using: 0 TPU cores\n",
|
|
"HPU available: False, using: 0 HPUs\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Epoch 1499: 100%|██████████| 1/1 [00:00<00:00, 66.39it/s, v_num=133, bound_cond_loss=5.38e-8, phys_cond_loss=2.58e-5, train_loss=2.59e-5] "
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"`Trainer.fit` stopped: `max_epochs=1500` reached.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Epoch 1499: 100%|██████████| 1/1 [00:00<00:00, 44.15it/s, v_num=133, bound_cond_loss=5.38e-8, phys_cond_loss=2.58e-5, train_loss=2.59e-5]\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"image/png": "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9OnTjcTERMf0+Q8//NCIjo42Hn/8ccc17tzeuro6Y926dca6desMScbLL79srFu3zjFDyhltq66uNuLi4ozbbrvN2LRpk/Huu+8agYGBpk2tPl2bm5ubjauuuspISkoy8vLy2v0cO35GlDu1+Ux/xj/0w1ljhuFe7XUGgpBJ/vznPxspKSmGv7+/kZGRYaxcudLsks6apJO+/vGPfziuOXTokHHfffcZERERRmBgoHHNNdcY+/fvb3efPXv2GJdffrnRvXt3Izo62nj00UeNlpaWLm7NuflhEPLE9v7nP/8xhg4dalitVmPgwIHG3/72t3bn7Xa78atf/cqIi4szrFarcckllxjbt29vd82BAweMqVOnGsHBwUZoaKhx5513GnV1dV3ZjA6pra01HnroISMlJcUICAgwevfubTz99NPtPhTdub2LFy8+6f+z06dPNwzDeW1bv369MWHCBMNqtRqJiYnGCy+80FVNPMHp2lxQUHDKn2OLFy923MOd2nymP+MfOlkQcqf2OoPFMI5bMhUAAMCLMEYIAAB4LYIQAADwWgQhAADgtQhCAADAaxGEAACA1yIIAQAAr0UQAgAAXosgBAAAvBZBCADOwpIlS2SxWE7YXBeAeyIIAQAAr0UQAgAAXosgBMCt2O12zZo1S7169VL37t01YsQIvf/++5KOPbZauHChhg8froCAAI0dO1abNm1qd48PPvhAQ4YMkdVqVWpqql566aV255uamvTEE08oOTlZVqtVffv21f/93/+1uyY3N1djxoxRYGCgLrjgAm3fvr1zGw6gUxCEALiVWbNm6c0339Trr7+uzZs365FHHtGtt96qb7/91nHNY489ppdeekmrV69WTEyMpkyZopaWFkltAebGG2/UzTffrI0bN+q5557Tr371K82ZM8fx/bfffrvmzp2rV155RVu3btVf//pXBQcHt6vj6aef1ksvvaQ1a9bIz89Pd911V5e0H4Bzsfs8ALfR1NSkyMhIff311xo3bpzj+M9+9jM1Njbqnnvu0cSJE/Xuu+/qpptukiRVVVUpKSlJc+bM0Y033qhp06apoqJCX375peP7H3/8cS1cuFCbN2/Wjh07NGDAAH311VfKyso6oYYlS5Zo4sSJ+vrrr3XJJZdIkj799FNdeeWVOnTokAICAjr5dwGAM9EjBMBt5Ofnq7GxUZdeeqmCg4MdrzfffFO7du1yXHd8SIqMjNSAAQO0detWSdLWrVs1fvz4dvcdP368du7cKZvNpry8PPn6+upHP/rRaWsZPny449c9evSQJJWXl593GwF0LT+zCwCAjqqvr5ckLVy4UImJie3OWa3WdmHoXHXv3r1D13Xr1s3xa4vFIqlt/BIA90KPEAC3MXjwYFmtVhUVFalv377tXsnJyY7rVq5c6fj1wYMHtWPHDg0aNEiSNGjQIC1fvrzdfZcvX67+/fvL19dXw4YNk91ubzfmCIDnokcIgNsICQnRL37xCz3yyCOy2+2aMGGCampqtHz5coWGhqpnz56SpN/85jeKiopSXFycnn76aUVHR+vqq6+WJD366KNKT0/X888/r5tuukkrVqzQq6++qr/85S+SpNTUVE2fPl133XWXXnnlFY0YMUKFhYUqLy/XjTfeaFbTAXQSghAAt/L8888rJiZGs2bN0u7duxUeHq5Ro0bpl7/8pePR1AsvvKCHHnpIO3fuVFpamv7zn//I399fkjRq1Ci99957euaZZ/T888+rR48e+s1vfqM77rjD8R6vvfaafvnLX+q+++7TgQMHlJKSol/+8pdmNBdAJ2PWGACPcXRG18GDBxUeHm52OQDcAGOEAACA1yIIAQAAr8WjMQAA4LXoEQIAAF6LIAQAALwWQQgAAHgtghAAAPBaBCEAAOC1CEIAAMBrEYQAAIDXIggBAACv9f8DCDnEgvLf5DEAAAAASUVORK5CYII=",
|
|
"text/plain": [
|
|
"<Figure size 640x480 with 1 Axes>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"from pina.callback import MetricTracker\n",
|
|
"\n",
|
|
"#create the model\n",
|
|
"newmodel = FeedForward(\n",
|
|
" layers=[10, 10],\n",
|
|
" func=torch.nn.Tanh,\n",
|
|
" output_dimensions=len(problem.output_variables),\n",
|
|
" input_dimensions=len(problem.input_variables)\n",
|
|
")\n",
|
|
"\n",
|
|
"# create the PINN object\n",
|
|
"newpinn = PINN(problem, newmodel, optimizer=TorchOptimizer(torch.optim.Adam, lr=0.005))\n",
|
|
"\n",
|
|
"# create the trainer\n",
|
|
"newtrainer = Trainer(solver=newpinn, max_epochs=1500, logger=True, #enable parameter logging\n",
|
|
" callbacks=[MetricTracker()],\n",
|
|
" accelerator='cpu',\n",
|
|
" train_size=1.0,\n",
|
|
" test_size=0.0,\n",
|
|
" val_size=0.0,\n",
|
|
" enable_model_summary=False) # we train on CPU and avoid model summary at beginning of training (optional)\n",
|
|
"\n",
|
|
"# train\n",
|
|
"newtrainer.train()\n",
|
|
"\n",
|
|
"#plot loss\n",
|
|
"trainer_metrics = newtrainer.callbacks[0].metrics\n",
|
|
"loss = trainer_metrics['train_loss']\n",
|
|
"epochs = range(len(loss))\n",
|
|
"plt.plot(epochs, loss.cpu())\n",
|
|
"# plotting\n",
|
|
"plt.xlabel('epoch')\n",
|
|
"plt.ylabel('loss')\n",
|
|
"plt.yscale('log') \n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "33e672da",
|
|
"metadata": {},
|
|
"source": [
|
|
"## What's next?\n",
|
|
"\n",
|
|
"Congratulations on completing the introductory tutorial of **PINA**! There are several directions you can go now:\n",
|
|
"\n",
|
|
"1. Train the network for longer or with different layer sizes and assert the finaly accuracy\n",
|
|
"\n",
|
|
"2. Train the network using other types of models (see `pina.model`)\n",
|
|
"\n",
|
|
"3. GPU training and speed benchmarking\n",
|
|
"\n",
|
|
"4. Many more..."
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.12.3"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|