{ "cells": [ { "attachments": {}, "cell_type": "markdown", "id": "6f71ca5c", "metadata": {}, "source": [ "# Tutorial: Physics Informed Neural Networks on PINA\n", "\n", "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](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", "

\n", " \"PINA\n", "

\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", "\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", "\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": null, "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", "\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", "\n", "class SimpleODE(SpatialProblem):\n", "\n", " output_variables = [\"u\"]\n", " spatial_domain = CartesianDomain({\"x\": [0, 1]})\n", "\n", " domains = {\n", " \"x0\": CartesianDomain({\"x\": 0.0}),\n", " \"D\": CartesianDomain({\"x\": [0, 1]}),\n", " }\n", "\n", " # conditions to hold\n", " conditions = {\n", " \"bound_cond\": Condition(domain=\"x0\", equation=FixedValue(1.0)),\n", " \"phys_cond\": Condition(domain=\"D\", equation=Equation(ode_equation)),\n", " }\n", "\n", " # defining the true solution\n", " def solution(self, pts):\n", " return torch.exp(pts.extract([\"x\"]))\n", "\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 `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 `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": null, "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": null, "id": "329962b6", "metadata": {}, "outputs": [], "source": [ "# sampling for training\n", "problem.discretise_domain(1, \"random\", domains=[\"x0\"])\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": null, "id": "d6ed9aaf", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Input points: {'x0': LabelTensor([[0.]]), 'D': LabelTensor([[0.3097],\n", " [0.9524],\n", " [0.6227],\n", " [0.9200],\n", " [0.1549],\n", " [0.8729],\n", " [0.8064],\n", " [0.3929],\n", " [0.1100],\n", " [0.4493],\n", " [0.2909],\n", " [0.6947],\n", " [0.0141],\n", " [0.4516],\n", " [0.5632],\n", " [0.5328],\n", " [0.7851],\n", " [0.0829],\n", " [0.7144],\n", " [0.2229]])}\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": null, "id": "3802e22a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "for location in problem.input_pts:\n", " coords = (\n", " problem.input_pts[location].extract(problem.spatial_variables).flatten()\n", " )\n", " plt.scatter(coords, torch.zeros_like(coords), s=10, label=location)\n", "plt.legend()" ] }, { "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": null, "id": "3bb4dc9b", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "GPU available: True (mps), 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, 149.92it/s, v_num=0, bound_cond_loss=1.52e-8, phys_cond_loss=7.68e-6, train_loss=7.69e-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, 100.10it/s, v_num=0, bound_cond_loss=1.52e-8, phys_cond_loss=7.68e-6, train_loss=7.69e-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(\n", " solver=pinn,\n", " max_epochs=1500,\n", " 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,\n", ") # 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": 27, "id": "f5fbf362", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'bound_cond_loss': tensor(1.5208e-08),\n", " 'phys_cond_loss': tensor(7.6781e-06),\n", " 'train_loss': tensor(7.6933e-06)}" ] }, "execution_count": 27, "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": null, "id": "ffbf0d5e", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqgAAAKTCAYAAADVBfoyAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8ekN5oAAAACXBIWXMAAA9hAAAPYQGoP6dpAABrjUlEQVR4nO3dB3gU5drG8XvTEyB0SOi9Q+i9KooNxQoWioBIs5cj9nbEo1iPCNJBpIgKNgQRBKQX6b330ElIIH2+6x1P+AADEkgyW/6/61qZ2Z3dPJtJzL1vG5dlWZYAAAAAN+HndAEAAADA+QioAAAAcCsEVAAAALgVAioAAADcCgEVAAAAboWACgAAALdCQAUAAIBbCZAXSEtL08GDB5UnTx65XC6nywEAAMBFzNL7p0+fVrFixeTn5+f9AdWE05IlSzpdBgAAAP7Bvn37VKJECe8PqKblNP0Nh4eHO10OAAAALhIbG2s3KKbnNq8PqOnd+iacElABAADc15UMx2SSFAAAANwKARUAAABuhYAKAAAAt+IVY1CvVGpqqpKTk50uA/AqgYGB8vf3d7oMAIAXCfCVdbeio6N16tQpp0sBvFK+fPkUERHBOsQAgCzhEwE1PZwWKVJEYWFh/BEFsvDD35kzZ3TkyBF7PzIy0umSAABeIMAXuvXTw2nBggWdLgfwOqGhofa/JqSa3zO6+wEA18rrJ0mljzk1LacAskf67xdjvAEAWcHrA2o6uvWB7MPvFwAgK/lMQAUAAIBnIKACAADAcwPqwIED1aBBA+XJk8eeDNGhQwdt2bLlss9p3bq13f138e3WW289d0y3bt3+9vhNN9109e8KOcqc4yeffFLe7vXXX1ft2rVz7OuNGTPGXr7pWs2dO9f+nWKZNQCAp8hUQJ03b5769eunJUuWaNasWfaEiBtvvFHx8fGXfM53332nQ4cOnbutX7/enuV77733XnCcCaTnHzdx4kT5uvTg/u67715w/7Rp0zxqzJ8JWhl96DCBydxvAlRmvifmgxGu/MNC06ZN7d+pvHnzOlYXAADZtszUjBkz/hY8TEvqypUr1bJlywyfU6BAgQv2J02aZM/4vTigBgcH2wt940IhISH6z3/+o0cffVT58+fP0a9tPoCYqwRlhYCAAP3222/6/fff1aZNG3naWp9muTJPFRQUxO8WAMB3xqDGxMRkGEIvZ+TIkerUqZNy5cp1wf2mFc2E3cqVK6tPnz46fvz4JV8jMTFRsbGxF9wyvbh4UoojN/O1M6Nt27Z2uDDDKy5nwYIFatGihb0mZcmSJfX4449f0LJtWipNy+v5TPex+ZBh7N692z5m8uTJatWqlR2Mv/rqK/s83H///SpevLj9waJmzZpX1bptznf37t31wgsvXPa4ffv26b777rNrMz9Xd9xxh11behf72LFj9f33358bCmJ+bu655x7179//3GuYFkTz2ObNm+39pKQk++ubgJz+82O+P+bnzbzP5s2ba/ny5X/rEv/ll19Ur149+8OT+f5ebMeOHSpXrpz9tTM6r+Y+U3OpUqXs1yhWrJj9ddOdPHlSXbp0sT94mO/tzTffrG3btmWq9di8V9Nqmv646eX45JNPzn1/zPcuoy7+b7/9VtWrV7frKlOmjD744IMLXtfc984779jnzAzpMe9h2LBhlz13AAA4vlB/Wlqa/cexWbNmqlGjxhU9Z9myZXYXvwmp5zNdv3fddZfKli1r/9F/8cUX7T/WixcvznDRbxPW3njjjastXWeTU1Xt1ZlywsY32yks6Mq/7eb9m6DwwAMP2OGmRIkSfzvGfM/M9/Dtt9/WqFGjdPToUTs0mdvo0aMzVZ8JkCas1KlTxw5vCQkJdkj717/+pfDwcP3888/q3Lmzypcvr4YNG2bqtU1Yq1Chgr755hs7VGbUYtuuXTs1adJEf/zxh93qat6TeW9r167Vs88+q02bNtkfSNLflwmx69at0xdffHHudUxIK1SokB3MqlSpYodP89qmq9t4/vnn7YBmwm7p0qX13nvv2V93+/btF3zYMt+LQYMG2SHUhMjzhyKYesxzevToYdeYEfM1PvroI7vXwIRBc0WzNWvWnHvcBEoTSH/44Qf7e2u+x7fccos2btx4VS3XJphu3brV/n1888037fsKFy58LuCnMz0e5kOAOR8dO3bUokWL1LdvX/tCFqamdObn4K233rJ/H805Mx8czYcX8yESAAC3bEE1Y1FN2DR/fK+UCaamBe7iYGNaVG+//Xb7MdNC9NNPP9mh4lJjEwcMGGC33qbfTKubN7vzzjvtyTmvvfZaho+bwP7ggw/aHxgqVqxoB7FPP/1U48aNswNmZpjXSP+wYC5baVpOTTA0X98Etccee8wOjF9//XWm34dpQXziiSf00ksvKSUl5W+Pm9Zb88FnxIgR9s9C1apV7SC6d+9e+2chd+7cdgtx+nAQczPd16YF0YQ6E8xNq6TZNl8n/efH/Gsm95lWStOqPGTIEL3//vv2h6Bq1app+PDh9ute/MHJhLwbbrjBDuPnB1cT6MzXNN+XS4VTw9RtajSt4KYF0vzcP/LII/Zj6cHUvFfT8h0VFWW3WB84cOBvLd1XyowxNd8P8z7Tvz8ZfcD78MMPdf311+uVV15RpUqV7FBqPsyY78n5TFg2wdV8qDDh2YR+M0QDAAC3bEE1f8xMiJw/f36GLXoZMcHAhNn0lp3LMUHI/DE0LVrmD+nFTEAxt6sVGuhvt2Q6wXztq2HGoV533XV2KLqYaZUzLXom4JzfvWzC3q5du+ygd6Xq169/wb4Ze2lacE0gNeHJdJebLvKrvTKXCTqmtdO09JpWvIvfhznnpkv5fCZkm1biSzEthiZAmpZTE9BM6+9tt92mwYMH24+b+9O7wc3rmNZU0/KfzrRWmvBoWmcv971ID50mtP773//+x5ULzDjrjz/+2P55NqHeBL727dvbLcPma5l/GzVqdO5404JpWicvriOrmdc3QyfOZ74fplZzvtNDba1atc49boYImMBrLmcKAIBbBVQTekwL2tSpU+1WKdPKdqWmTJliB5uHHnroH4/dv3+/PfbRtOBlB/PHNjPd7O7ATEIzXcqm9fj8blgjLi7OnkR1/vjGdKblLv09XzxOMqPLUl48Nti0qpmuYxNeTKumedwEMxNUr4YZW2regxmiYULkxe/DDCc4P2inM13Vl2Lem/n+mJ9J88HFhFETrszPm2nlNy2eGQX7f3Lx9yK9DtMSbMbhmvGZpmv+UsxYYLMMmxn7ala9MK2R5vtpAvPV8PPzu6JzmFUuHmZgvs/mQw8AAG7VxW+69cePH68JEybYrVxmTJ25nT179twxZtKHCSAXM92npvvetBJdHEqee+45e+kqM1Zu9uzZduuO6VY0gQz/zyw39eOPP9pjc89Xt25du1vbfM8uvpkWxfRgZZYaSme6mM+cOfOPX3PhwoX2+TAfLEw3tGkNNOMcr4X5kGPClgm+F78PU5eZvHTx+0hfIsm8n4xm1JuxkSagmpsJqOb1TWg1gdAE1fQWU9Ndb17DvK/zQ54ZUmK6+/+JGQpgeg/M+Fzz83n69Ol/PN60mpohF6Y2c+7MmFnTqm2GOSxduvTcseZDmQm0l6rj4nNorF69+oL9S31/zme+9vnv3zD7prs/oyEBAAC4dUA1Y/fMmE8TAEzrZvrNjB08vwv04j+i5o+umQVtJpRczPxBNN3TZgyq+QNpjjGtaGaSzLV043sj04JpxpqasHNxt7lpJTRDL0xgMSHPzHQ/f2a7GR7w2WefadWqVVqxYoV69+59RRNxzJhW0/pnXt90DZuW2sOHD1/T+zDhzrSgXvw+zHszQztMIDbn3wxPMKHOtAybVvX02eXm58X8TB07duxcC2L6ONQNGzbYs/LT7zOtsaarPr011PxrJvuYD0Vm2TTzHDMu1IT1jH4+M2Jew0wWM130Zhyr+ZCVEbNCgvlgZlpxd+7caX+4M4HVTMwy31fzPs3XNr8bZniD+RBgxvxe3P1+/jk0586MLTbn2IxJNq99PvP9MaHXfNgz35+MWjyfeeYZ+4OgmQBlPmyYyWLmZ+NqWpkBAHA8oJruxYxu53c5m0CRvnRROjOuzhxnxu5dzPzBnjlzpj22zXQbmz+sZjmbokWLXsv78lpmDO/FocN0Z5tuYxM2zIQbMwbz1Vdftbuiz5+RbbqczeNmRQATRq5kHOnLL79st2ya1kIT+Mw4xKxYKL9r1652a+z5TD1mXLMZlmAmapmWPhMazRjU9K50E+jMz5MJnaZFMb0l0IR3M3zATOYyk6kMU69pTUwff3p+S/Tdd99tr0Zg3psZ92p+BjOzzqz5GmYZKvNzba6KltHFKkw9ZgKWab0158h09ZsW8PReBDMBzHwYM0MdzMoF5rWmT59+yQ8O5hyYiU1mFQIz6cu03poei/OZ82o+9JlWWPP9MR8YL2besxlTbMaEm/G75mfF/FxdPHQEAACnuKzMLszphsyyQ6YL2LTuXjwm0IQb0xJnxsualjsAWY/fMwDAteS1LF2oHwAAAB4qNUVKzb7JtteCgAoAAOCDomd9pBMfN5d1YJXcDQEVAADAxyQf3aF8S95XgdObNXvuX5cCdycEVAAAAF9iWYr+qrdClKilqqGo9o/J3RBQAQAAfMjh+aNU8tQyJViBOnndeyoc7n6TWwmoAAAAPiItNlphc1+1t6fl76Z2LZrKHRFQAQAAfMSer/orjxWnDVZZtejymn0Za3dEQAUAAPABR5d/p7KHZynF8tOuZu+qeIE8clcEVGQrc2Ux8+ns1KlT1/Q65gpj5nUuvvY8AAD4Z9bZU/Kf8dclrX/KfY9uadtO7oyA6qZMGLvc7fXXX5e3MpfcvPhyquYyrYcOHbIvzQkAADJn58RnVSD1uHZbEardeaD8/Nyzaz9dgNMFIGMmjKWbPHmyfb30LVu2nLsv/XrzhrlarbnmfECA955Oc335iIgIp8sAAMDjnNz4u8rvnWJvr63zpm6PKCR3RwuqmzJhLP1mrltrWk3T9zdv3qw8efLol19+Ub169RQcHKwFCxZk2PL45JNPqnXr1uf209LSNHDgQPua6aGhoYqKitI333xz2Vo+//xzVaxY0b7GetGiRXXPPfeceywxMVGPP/64ihQpYj/evHlzLV++/JKvZVp+a9eufcF9H3/8scqUKXPu8bFjx+r7778/11pshglk1MU/b948NWzY0H7/kZGReuGFF5SSknLucfO+TW3PP/+8ChQoYH/vvLnlGQCAi1nJZ5U4tb+9PTO4nW5pf688gfc2uV2OZUnJZ5z52oFhpv8+S17KBLJBgwapXLlyyp8//xU9x4TT8ePHa+jQoXbonD9/vh566CEVLlxYrVq1+tvxK1assEPel19+qaZNm+rEiRP6448/zj1uwt+3335rh8rSpUvrvffeU7t27bR9+3Y7FGbWs88+q02bNik2NlajR4+27zOvc/DgwQuOO3DggG655RY7lI8bN84O7Y888ogdks8Poaaup59+WkuXLtXixYvt45s1a6Ybbrgh07UBAOBpdnzzmiok79cRK5/K3P+BAvw9o23SNwOqCafvFHPma794UArKlSUv9eabb2YqaJnWznfeeUe//fabmjRpYt9nwq1pff3iiy8yDKh79+5Vrly5dNttt9mttiaE1qlTx34sPj5eQ4YM0ZgxY3TzzTfb9w0fPlyzZs3SyJEj9dxzz2X6PZmhC6Zl19R6uS5906prxqV+9tlndstqlSpV7BD7r3/9yx4O4ef31y9grVq19Nprr9nbJpCb42fPnk1ABQB4vdhdf6rMlhH29pKqA3R7mZLyFL4ZUL1E/fr1M3W8adU8c+bM38JZUlLSudB5MXOsCaUmyN5000327c4771RYWJh27Nih5ORku0UyXWBgoN3tblpBs5N5fROyz1+/zdQRFxen/fv3q1SpUucC6vnMUIAjR45ka20AADguNUWnJvdWuFL1R0AT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TZo0yb7scYcOHbK9RmTtOTx16pT69eunyMhIe+mbSpUq8f9SDzp/H3/8sSpXrqzQ0FD7EppPPfWUEhIScqxeXGj+/Plq3769fWlR8//EadOm6Z/MnTtXdevWtX//KlSooDFjxsgRZpkp/N2kSZOsoKAga9SoUdaGDRusRx55xMqXL591+PDhDI9fuHCh5e/vb7333nvWxo0brZdfftkKDAy01q1bl+O1I/Pn74EHHrAGDx5srVq1ytq0aZPVrVs3K2/evNb+/ftzvHZc3TlMt2vXLqt48eJWixYtrDvuuCPH6sW1n8PExESrfv361i233GItWLDAPpdz5861Vq9eneO1I/Pn76uvvrKCg4Ptf825mzlzphUZGWk99dRTOV47/jJ9+nTrpZdesr777juzpKg1depU63J27txphYWFWU8//bSdZf773//a2WbGjBlWTiOgXkLDhg2tfv36ndtPTU21ihUrZg0cODDD4++77z7r1ltvveC+Ro0aWY8++mi214prP38XS0lJsfLkyWONHTs2G6tEVp9Dc96aNm1qjRgxwuratSsB1cPO4ZAhQ6xy5cpZSUlJOVglsur8mWOvu+66C+4zQadZs2bZXiv+2ZUE1Oeff96qXr36Bfd17NjRateunZXT6OLPQFJSklauXGl386bz8/Oz9xcvXpzhc8z95x9vtGvX7pLHw73O38XOnDmj5ORkFShQIBsrRVafwzfffFNFihRRjx49cqhSZOU5/OGHH9SkSRO7i79o0aKqUaOG3nnnHaWmpuZg5bja89e0aVP7OenDAHbu3GkPz7jllltyrG5cG3fKMgE5/hU9wLFjx+z/IZr/QZ7P7G/evDnD50RHR2d4vLkf7n/+Lvavf/3LHrNz8S8q3PccLliwQCNHjtTq1atzqEpk9Tk0gWbOnDl68MEH7WCzfft29e3b1/6waC7HCPc+fw888ID9vObNm5veWaWkpKh379568cUXc6hqXKtLZZnY2FidPXvWHlucU2hBBS7y7rvv2pNspk6dak8MgPs7ffq0OnfubE92K1SokNPl4CqlpaXZLeDDhg1TvXr11LFjR7300ksaOnSo06XhCpjJNabF+/PPP9eff/6p7777Tj///LPeeustp0uDB6IFNQPmD5y/v78OHz58wf1mPyIiIsPnmPszczzc6/ylGzRokB1Qf/vtN9WqVSubK0VWncMdO3Zo9+7d9mzV88OOERAQoC1btqh8+fI5UDmu5ffQzNwPDAy0n5euatWqdquO6XIOCgrK9rpx9efvlVdesT8o9uzZ0943q9nEx8erV69e9gcNM0QA7i3iElkmPDw8R1tPDX5aMmD+J2g+vc+ePfuCP3Zm34yPyoi5//zjjVmzZl3yeLjX+TPee+89+5P+jBkzVL9+/RyqFllxDs3ybuvWrbO799Nvt99+u9q0aWNvm+Vu4P6/h82aNbO79dM/XBhbt261gyvh1P3Pnxm7f3EITf+w8dccHbi7Ju6UZXJ8WpYHLa9hlssYM2aMvdRCr1697OU1oqOj7cc7d+5svfDCCxcsMxUQEGANGjTIXqbotddeY5kpDzp/7777rr2cyjfffGMdOnTo3O306dMOvgvfltlzeDFm8XveOdy7d6+9ekb//v2tLVu2WD/99JNVpEgR6+2333bwXfiuzJ4/83fPnL+JEyfayxX9+uuvVvny5e1VbuCM06dP28snmpuJfB9++KG9vWfPHvtxc/7Mebx4mannnnvOzjJm+UWWmXJDZv2vUqVK2cHFLLexZMmSc4+1atXK/gN4vq+//tqqVKmSfbxZpuHnn392oGpczfkrXbq0/ct78c38Dxee8zt4PgKqZ57DRYsW2Uv0mWBklpz697//bS8fBvc/f8nJydbrr79uh9KQkBCrZMmSVt++fa2TJ086VD1+//33DP+2pZ838685jxc/p3bt2vY5N7+Do0ePdqR2l/lPzrfbAgAAABljDCoAAADcCgEVAAAAboWACgAAALdCQAUAAIBbIaACAADArRBQAQAA4FYIqAAAAHArBFQAAAC4FQIqAAAA3AoBFQAAAG6FgAoAAAC5k/8DM2iGZydAHzYAAAAASUVORK5CYII=", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "pts = pinn.problem.spatial_domain.sample(256, \"grid\", variables=\"x\")\n", "predicted_output = pinn.forward(pts).extract(\"u\").tensor.detach()\n", "true_output = pinn.problem.solution(pts).detach()\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": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "To load TensorBoard run load_ext tensorboard on your terminal\n", "To visualize the loss you can run tensorboard --logdir 'tutorial_logs' on your terminal\n", "\n", "The tensorboard extension is already loaded. To reload it, use:\n", " %reload_ext tensorboard\n" ] }, { "data": { "text/plain": [ "Reusing TensorBoard on port 6007 (pid 55149), started 0:00:03 ago. (Use '!kill 55149' to kill it.)" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", " \n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "print(\"\\nTo load TensorBoard run load_ext tensorboard on your terminal\")\n", "print(\n", " \"To visualize the loss you can run tensorboard --logdir 'tutorial_logs' on your terminal\\n\"\n", ")\n", "# # uncomment for running tensorboard\n", "# %load_ext tensorboard\n", "# %tensorboard --logdir=tutorial_logs" ] }, { "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": null, "id": "03398692", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "GPU available: True (mps), 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, 211.36it/s, v_num=0, bound_cond_loss=3.6e-8, phys_cond_loss=2.13e-5, train_loss=2.13e-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, 134.97it/s, v_num=0, bound_cond_loss=3.6e-8, phys_cond_loss=2.13e-5, train_loss=2.13e-5]\n" ] }, { "data": { "image/png": "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NXO95sb1mp/VrjnYRNd7qp4gO4qlAQCAZRGEAACAZRGEDOLj4yNPPPGEvrUKq10z12tuXK/5We2afSx2vXYUSwMAAMuiRwgAAFgWQQgAAFgWQQgAAFgWQQgAAFgWQcggc+fOlaSkJPH19ZWRI0fK2rVrxdXMnj1bhg8frlfd7tChg1xxxRWye/fuJq+pqKiQ6dOnS0REhAQGBspVV10lWVlZTV6TlpYml112mfj7++uv8/DDD0tNTY04u2effVavNn7//feb+noPHTokN954o74mPz8/6d+/v6xfv77heTXfYtasWdKxY0f9/Pjx42Xv3r1NvkZ+fr7ccMMNepG20NBQ+d3vficlJSXibGpra+Xxxx+Xzp0762vp2rWrPP300032KnLl612+fLlMnjxZr7SrfnYXLFjQ5HlHXduWLVvkvPPO0+9vaqXi5557Tpzxmqurq+WPf/yj/pkOCAjQr7n55pv1bgKues0t/R03dscdd+jXzJkzx2Wv1yHUrDG0r48++sjm7e1te+edd2zbt2+33XbbbbbQ0FBbVlaWzZVMnDjR9q9//cu2bds226ZNm2yXXnqpLSEhwVZSUtLwmjvuuMMWHx9vW7x4sW39+vW2c845xzZ69OiG52tqamz9+vWzjR8/3vbLL7/YvvnmG1tkZKRt5syZNme2du1aW1JSkm3AgAG2++67z7TXm5+fb0tMTLTdcssttjVr1tj2799v+/77723JyckNr3n22WdtISEhtgULFtg2b95su/zyy22dO3e2lZeXN7zmkksusQ0cONC2evVq24oVK2zdunWzXX/99TZn85e//MUWERFh++qrr2wpKSm2Tz75xBYYGGh76aWXTHG96uftscces3322Wcq2dk+//zzJs874toKCwtt0dHRthtuuEG/N3z44Yc2Pz8/25tvvmlztmsuKCjQv4vz58+37dq1y7Zq1SrbiBEjbEOHDm3yNVzpmlv6O7ZTz6trio2Ntf3973932et1BIKQAdQv2vTp0xvu19bW6h/G2bNn21xZdna2/sVbtmxZw5uMl5eX/jCx27lzp36NesOx/9K6u7vbMjMzG17z+uuv24KDg22VlZU2Z1RcXGzr3r277YcffrBdcMEFDUHIjNf7xz/+0TZmzJhmn6+rq7PFxMTY/va3vzU8pv4cfHx89JujsmPHDv1nsG7duobXfPvttzY3NzfboUOHbM7ksssus916661NHvvNb36j3/DNdr3Hf0g66tpee+01W1hYWJOfZ/Vz1LNnT5vRThUMGv8jR70uNTXV5a+5ues9ePCgrVOnTjrEJCYmNglCrny9Z4qhsXZWVVUlGzZs0F3OjfczU/dXrVolrqywsFDfhoeH61t1narrufG19urVSxISEhquVd2qbuno6OiG10ycOFFv/rd9+3ZxRmroSw1tNb4us17v//73Pxk2bJhcc801ehhv8ODB8vbbbzc8n5KSIpmZmU2uWe3to4Z7G1+z6l5XX8dOvV793K9Zs0acyejRo2Xx4sWyZ88efX/z5s2ycuVKmTRpkimvtzFHXZt6zfnnny/e3t5NfsbVsPmRI0fEFd7H1HCRuk4zXrPaSPymm27SQ/J9+/Y94XmzXW9rEITaWW5urq5DaPxBqKj76k3IValfLlUrc+6550q/fv30Y+p61C+K/Q3lZNeqbk/2Z2F/ztl89NFHsnHjRl0fdTwzXu/+/fvl9ddfl+7du8v3338vd955p9x7773y7rvvNmnzqX6e1a0KUY15enrqwOxs1/zoo4/KddddpwOsl5eXDn7q51rVS5jxehtz1LW52s94Y6rGT9UMXX/99Q2bjprtmv/617/q9qvf45PJNNn1tga7z8NhvSTbtm3T/3o2q/T0dLnvvvvkhx9+0AWCVqACrvqX4TPPPKPvq2Cg/p7feOMNmTp1qpjNxx9/LP/5z3/kgw8+0P9a3rRpkw5CqvDUjNeLY1Rv7rXXXqsLxlX4NyPVa/3SSy/pf8ypXi/Uo0eonUVGRoqHh8cJM4nU/ZiYGHFFd999t3z11VeyZMkSiYuLa3hcXY8aCiwoKGj2WtXtyf4s7M8525tIdna2DBkyRP8LSR3Lli2Tl19+WZ+rfxGZ6XoVNXuoT58+TR7r3bu3nvnWuM2n+nlWt+rPrTE1S07NTHG2a1bDBfZeITWEqYYQHnjggYYeQLNdb2OOujZX+xlvHIJSU1P1P3TsvUFmu+YVK1boa1HD9fb3sNTUVJkxY4aexWy2620tglA7U0MnQ4cO1XUIjf/Vre6PGjVKXIn6l5MKQZ9//rn8+OOPespxY+o61fBC42tVY8jqQ9R+rep269atTX7x7G9Ex38AG23cuHG6raqXwH6o3hI1bGI/N9P1Kmqo8/glEVT9TGJioj5Xf+fqja/xNat6J1VL0PiaVThUQdJO/byon3tVf+JMysrKdC1EY+ofLqqtZrzexhx1beo1agq3CheNf8Z79uwpYWFh4qwhSC0TsGjRIr1MRGNmumYV7NW098bvYbGxsfofAGro22zX22pGV2tbdfq8mokxb948XaF/++236+nzjWcSuYI777xTT7VdunSp7fDhww1HWVlZk+nkakr9jz/+qKeTjxo1Sh/HTye/+OKL9RT87777zhYVFeW008mP13jWmBmvV82g8fT01NPK9+7da/vPf/5j8/f3t73//vtNplyrn98vvvjCtmXLFtuvf/3rk065Hjx4sJ6Cv3LlSj3rzhmmkx9v6tSpejaNffq8mmKsljd45JFHTHG9asajWrZBHert/8UXX9Tn9hlSjrg2NdNMTa2+6aab9Kwk9X6nfmaMmlp9qmuuqqrSSwTExcXp38fG72ONZ0S50jW39Hd8vMTjZo252vU6AkHIIK+88or+wFTrCanp9Gq9BlejfslOdqi1hezUG+hdd92lp1qqX5Qrr7xSv8k0duDAAdukSZP0OhTqQ2fGjBm26upqmysGITNe75dffqnDmwrvvXr1sr311ltNnlfTrh9//HH9xqheM27cONvu3bubvCYvL0+/kao1edRSAdOmTdNv2M6mqKhI/32q301fX19bly5d9JosjT8UXfl6lyxZctLfWRUAHXltag0iteyC+hoqWKqA5YzXrMJuc+9j6v9zxWtu6e+4NUEoz4Wu1xHc1H+M7pUCAAAwAjVCAADAsghCAADAsghCAADAsghCAADAsghCAADAsghCAADAsghCAADAsghCAADAsghCAHAali5dqnfuPn5zXQCuiSAEAAAsiyAEAAAsiyAEwKXU1dXJ7NmzpXPnzuLn5ycDBw6UTz/9tMmw1ddffy0DBgwQX19fOeecc2Tbtm1NvsZ///tf6du3r/j4+EhSUpK88MILTZ6vrKyUP/7xjxIfH69f061bN/nnP//Z5DUbNmyQYcOGib+/v4wePVp2797dDlcPwNEIQgBcigpB7733nrzxxhuyfft2eeCBB+TGG2+UZcuWNbzm4Ycf1uFm3bp1EhUVJZMnT5bq6uqGAHPttdfKddddJ1u3bpUnn3xSHn/8cZk3b17D/3/zzTfLhx9+KC+//LLs3LlT3nzzTQkMDGzSjscee0x/j/Xr14unp6fceuut7finAMBR2H0egMtQPTXh4eGyaNEiGTVqVMPjv//976WsrExuv/12GTt2rHz00UcyZcoU/Vx+fr7ExcXpoKMC0A033CA5OTmycOHChv//kUce0b1IKljt2bNHevbsKT/88IOMHz/+hDaoXif1PVQbxo0bpx/75ptv5LLLLpPy8nLdCwXAddAjBMBlJCcn68AzYcIE3UNjP1QP0b59+xpe1zgkqeCkgo3q2VHU7bnnntvk66r7e/fuldraWtm0aZN4eHjIBRdccMq2qKE3u44dO+rb7Oxsh10rgPbh2U7fBwDOWklJib5VvTedOnVq8pyq5Wkchs6UqjtqDS8vr4ZzVZdkr18C4FroEQLgMvr06aMDT1pami5gbnyowma71atXN5wfOXJED3f17t1b31e3P/30U5Ovq+736NFD9wT1799fB5rGNUcAzIseIQAuIygoSB566CFdIK3CypgxY6SwsFAHmeDgYElMTNSv+/Of/ywRERESHR2ti5ojIyPliiuu0M/NmDFDhg8fLk8//bSuI1q1apW8+uqr8tprr+nn1SyyqVOn6uJnVSytZqWlpqbqYS9VYwTAXAhCAFyKCjBqJpiaPbZ//34JDQ2VIUOGyJ/+9KeGoalnn31W7rvvPl33M2jQIPnyyy/F29tbP6de+/HHH8usWbP011L1PSo43XLLLQ3f4/XXX9df76677pK8vDxJSEjQ9wGYD7PGAJiGfUaXGg5TAQkAWkKNEAAAsCyCEAAAsCyGxgAAgGXRIwQAACyLIAQAACyLIAQAACyLIAQAACyLIAQAACyLIAQAACyLIAQAACyLIAQAAMSq/j/Ul/MkD3RaGQAAAABJRU5ErkJggg==", "text/plain": [ "
" ] }, "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(\n", " problem, newmodel, optimizer=TorchOptimizer(torch.optim.Adam, lr=0.005)\n", ")\n", "\n", "# create the trainer\n", "newtrainer = Trainer(\n", " solver=newpinn,\n", " max_epochs=1500,\n", " 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,\n", ") # 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\")" ] }, { "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": "pina", "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.9.21" } }, "nbformat": 4, "nbformat_minor": 5 }