diff --git a/examples/Training a M3GNet Formation Energy Model with PyTorch Lightning.ipynb b/examples/Training a M3GNet Formation Energy Model with PyTorch Lightning.ipynb new file mode 100644 index 00000000..9a2b2339 --- /dev/null +++ b/examples/Training a M3GNet Formation Energy Model with PyTorch Lightning.ipynb @@ -0,0 +1,642 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "35c97a76", + "metadata": {}, + "source": [ + "# Introduction\n", + "\n", + "This notebook demonstrates how to refit a MEGNet formation energy model using PyTorch Lightning with MatGL." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6355190a", + "metadata": {}, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import os\n", + "import shutil\n", + "import warnings\n", + "import zipfile\n", + "from functools import partial\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import pandas as pd\n", + "import pytorch_lightning as pl\n", + "from dgl.data.utils import split_dataset\n", + "from pymatgen.core import Structure\n", + "from pytorch_lightning.loggers import CSVLogger\n", + "from tqdm import tqdm\n", + "\n", + "from matgl.ext.pymatgen import Structure2Graph, get_element_list\n", + "from matgl.graph.data import M3GNetDataset, MGLDataLoader, collate_fn\n", + "from matgl.models import M3GNet\n", + "from matgl.utils.io import RemoteFile\n", + "from matgl.utils.training import ModelLightningModule\n", + "\n", + "# To suppress warnings for clearer output\n", + "warnings.simplefilter(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "id": "eaafc0bd", + "metadata": {}, + "source": [ + "# Dataset Preparation\n", + "\n", + "We will download the original dataset used in the training of the MEGNet formation energy model (MP.2018.6.1) from figshare. To make it easier, we will also cache the data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ad359f9f", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "69239it [03:54, 295.16it/s] \n" + ] + } + ], + "source": [ + "def load_dataset() -> tuple[list[Structure], list[str], list[float]]:\n", + " \"\"\"Raw data loading function.\n", + "\n", + " Returns:\n", + " tuple[list[Structure], list[str], list[float]]: structures, mp_id, Eform_per_atom\n", + " \"\"\"\n", + " if not os.path.exists(\"mp.2018.6.1.json\"):\n", + " f = RemoteFile(\"https://figshare.com/ndownloader/files/15087992\")\n", + " with zipfile.ZipFile(f.local_path) as zf:\n", + " zf.extractall(\".\")\n", + " data = pd.read_json(\"mp.2018.6.1.json\")\n", + " structures = []\n", + " mp_ids = []\n", + " for mid, structure_str in tqdm(zip(data[\"material_id\"], data[\"structure\"])):\n", + " struct = Structure.from_str(structure_str, fmt=\"cif\")\n", + " structures.append(struct)\n", + " mp_ids.append(mid)\n", + "\n", + " return structures, mp_ids, data[\"formation_energy_per_atom\"].tolist()\n", + "\n", + "\n", + "structures, mp_ids, eform_per_atom = load_dataset()" + ] + }, + { + "cell_type": "markdown", + "id": "cdfb699c", + "metadata": {}, + "source": [ + "For demonstration purposes, we are only going to select 100 structures from the entire set of structures to shorten the training time." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4e5b1c87", + "metadata": {}, + "outputs": [], + "source": [ + "structures = structures[:100]\n", + "eform_per_atom = eform_per_atom[:100]" + ] + }, + { + "cell_type": "markdown", + "id": "a62b0271", + "metadata": {}, + "source": [ + "Here, we set up the dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52ccef45", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 100/100 [00:00<00:00, 346.60it/s]\n" + ] + } + ], + "source": [ + "# get element types in the dataset\n", + "elem_list = get_element_list(structures)\n", + "# setup a graph converter\n", + "converter = Structure2Graph(element_types=elem_list, cutoff=4.0)\n", + "# convert the raw dataset into MEGNetDataset\n", + "mp_dataset = M3GNetDataset(\n", + " threebody_cutoff=4.0, structures=structures, converter=converter, labels={\"eform\": eform_per_atom}\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "afc0e761", + "metadata": {}, + "source": [ + "We will then split the dataset into training, validation and test data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a6f29ef3", + "metadata": {}, + "outputs": [], + "source": [ + "train_data, val_data, test_data = split_dataset(\n", + " mp_dataset,\n", + " frac_list=[0.8, 0.1, 0.1],\n", + " shuffle=True,\n", + " random_state=42,\n", + ")\n", + "my_collate_fn = partial(collate_fn, include_line_graph=True)\n", + "train_loader, val_loader, test_loader = MGLDataLoader(\n", + " train_data=train_data,\n", + " val_data=val_data,\n", + " test_data=test_data,\n", + " collate_fn=my_collate_fn,\n", + " batch_size=2,\n", + " num_workers=1,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "16e5e4db", + "metadata": {}, + "source": [ + "# Model setup\n", + "\n", + "In the next step, we setup the model and the ModelLightningModule. Here, we have initialized a MEGNet model from scratch. Alternatively, you can also load one of the pre-trained models for transfer learning, which may speed up the training." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ed2d0653", + "metadata": {}, + "outputs": [], + "source": [ + "# setup the architecture of MEGNet model\n", + "model = M3GNet(\n", + " element_types=elem_list,\n", + " is_intensive=True,\n", + " readout_type=\"set2set\",\n", + " )\n", + "# setup the MEGNetTrainer\n", + "lit_module = ModelLightningModule(model=model)" + ] + }, + { + "cell_type": "markdown", + "id": "01be4689", + "metadata": {}, + "source": [ + "# Training\n", + "\n", + "Finally, we will initialize the Pytorch Lightning trainer and run the fitting. Note that the max_epochs is set at 20 to demonstrate the fitting on a laptop. A real fitting should use max_epochs > 100 and be run in parallel on GPU resources. For the formation energy, it should be around 2000. The `accelerator=\"cpu\"` was set just to ensure compatibility with M1 Macs. In a real world use case, please remove the kwarg or set it to cuda for GPU based training. You may also need to use `torch.set_default_device(\"cuda\")` or `with torch.device(\"cuda\")` to ensure all data are loaded onto the GPU for training.\n", + "\n", + "We have also initialized the Pytorch Lightning Trainer with a `CSVLogger`, which provides a detailed log of the loss metrics at each epoch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7472d071", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "GPU available: False, used: False\n", + "TPU available: False, using: 0 TPU cores\n", + "IPU available: False, using: 0 IPUs\n", + "HPU available: False, using: 0 HPUs\n", + "\n", + " | Name | Type | Params\n", + "--------------------------------------------\n", + "0 | model | M3GNet | 388 K \n", + "1 | mae | MeanAbsoluteError | 0 \n", + "2 | rmse | MeanSquaredError | 0 \n", + "--------------------------------------------\n", + "388 K Trainable params\n", + "0 Non-trainable params\n", + "388 K Total params\n", + "1.553 Total estimated model params size (MB)\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Sanity Checking: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "825082d9d040431f88a924808e602985", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Training: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Validation: 0it [00:00, ?it/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "`Trainer.fit` stopped: `max_epochs=20` reached.\n" + ] + } + ], + "source": [ + "logger = CSVLogger(\"logs\", name=\"M3GNet_training\")\n", + "trainer = pl.Trainer(max_epochs=20, accelerator=\"cpu\", logger=logger)\n", + "trainer.fit(model=lit_module, train_dataloaders=train_loader, val_dataloaders=val_loader)" + ] + }, + { + "cell_type": "markdown", + "id": "256e10e2", + "metadata": {}, + "source": [ + "# Visualizing the convergence\n", + "\n", + "Finally, we can plot the convergence plot for the loss metrics. You can see that the MAE is already going down nicely with 20 epochs. Obviously, this is nowhere state of the art performance for the formation energies, but a longer training time should lead to results consistent with what was reported in the original MEGNet work." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2aa58a7c", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8o6BhiAAAACXBIWXMAAA9hAAAPYQGoP6dpAABXeElEQVR4nO3dd3hUVf7H8ffMpPdQ0hMIHaVJKIKCCIqiYldEEBBdxdVVFsvKujaW3+K6ruKugrpSRFFRxLKKIq7SBBQQFAGpgVASQijpdeb+/rgkEJJAJpnJpHxezzNPZu7cuXMuV8mHc8/5HothGAYiIiIiHmL1dANERESkaVMYEREREY9SGBERERGPUhgRERERj1IYEREREY9SGBERERGPUhgRERERj1IYEREREY/y8nQDqsPhcHDo0CGCg4OxWCyebo6IiIhUg2EYZGdnExMTg9Vadf9Hgwgjhw4dIj4+3tPNEBERkRrYv38/cXFxVb7fIMJIcHAwYJ5MSEiIh1sjIiIi1ZGVlUV8fHzZ7/GqNIgwUnprJiQkRGFERESkgTnXEAsNYBURERGPUhgRERERj1IYEREREY9qEGNGRESk4TMMg5KSEux2u6ebIi5is9nw8vKqddkNhREREXG7oqIiUlNTycvL83RTxMUCAgKIjo7Gx8enxsdQGBEREbdyOBwkJydjs9mIiYnBx8dHBSwbAcMwKCoq4siRIyQnJ9O+ffuzFjY7G4URERFxq6KiIhwOB/Hx8QQEBHi6OeJC/v7+eHt7s2/fPoqKivDz86vRcTSAVURE6kRN/9Us9Zsrrqv+yxARERGPUhgRERERj1IYERERqQOtW7dm+vTpnm5GvaQwIiIiUoVBgwYxceJElxxr3bp13HPPPS451t69e7FYLHh5eXHw4MFy76WmppbV/ti7d2+Fzw4dOhSbzcbatWsrvDdu3DgsFkuFx5VXXumSdldFYaSajuYU8o8lv/H0p796uikiIlJPlBZyq46WLVu6fDZRTEwM8+bNK7ftrbfeIjY2ttL9U1JSWLNmDQ888ACzZs2qdJ8rr7yS1NTUco/33nvPpe0+k8JINdkdBq9+t5u31+6j2O7wdHNERBo0wzDIKyqp84dhGNVu47hx41i+fDkvv/xyWQ/B3LlzsVgsLFmyhF69euHr68vKlSvZvXs31113HZGRkQQFBdG7d2+++eabcsc78zaNxWLhzTff5IYbbiAgIID27dvz2WefOfXnOHbsWObMmVNu29y5cxk7dmyl+8+ZM4drrrmG++67jwULFpCbm1thH19fX6Kioso9wsPDnWqXs1RnpJpaBPniY7NSZHeQlllAfDPNlRcRqan8YjvnPbWkzr9365QrCPCp3q++l19+mR07dtClSxemTJkCwJYtWwB47LHHeOGFF2jTpg1hYWEcOHCAq666iqlTp+Ln58dbb73F8OHD2b59OwkJCVV+x7PPPsvzzz/PP/7xD/79738zatQo9u3bR7NmzarVxmuvvZbXXnuNVatWcfHFF7Nq1SqOHTvG8OHD+etf/1puX8MwmDNnDq+++iqdOnWiQ4cOfPDBB9x5553V+i53Us9INVmtFmLCzGIuB47ne7g1IiLibqGhofj4+BAQEFDWQ2Cz2QCYMmUKl19+OW3btqV58+Z0796de++9l65du9K+fXumTp1KmzZtztnTMW7cOEaOHEm7du3429/+Rm5uLj/++GO12+jt7c3o0aOZPXs2ALNnz2b06NF4e3tX2Pebb74hLy+PK664AoDRo0dXeqvm888/JygoqNzjzGDjauoZcUJceAB7j+Zx8ITCiIhIbfh729g65QqPfK8r9OrVq9zr3Nxcnn32WT7//HMOHTpESUkJ+fn5pKSknPU43bp1K3seGBhIcHAw6enpTrXlrrvuol+/fvztb3/jww8/ZM2aNZWOY5k1axYjRozAy8v81T9y5EgeffRRtm/fTseOHcv2u/TSS5k5c2a5z1a3p6amFEacEBvmD8CB41roSUSkNiwWS7Vvl9RHgYGB5V4/+uijLFmyhBdeeIF27drh7+/PzTffTFFR0VmPc2YPhsViweFwblxily5d6NSpEyNHjqRz58506dKFTZs2ldvn2LFjfPLJJxQXF5cLGna7ndmzZ/P3v/+93Lm1a9fOqTbUVsP9L8EDYsPNMHJQt2lERJoEHx8f7Hb7OfdbuXIl48aN44YbbgAgJyen0mm17jJ+/Hh+//vfV+jRKDV//nzi4uL45JNPym3/3//+x7Rp0/i///u/sh4TT1AYcUJpz4hu04iINA2tW7fmhx9+YO/evQQFBVXZa9GuXTsWLVrE8OHDsVgsPPnkk073cNTG7373O2655RbCwsIqfX/WrFncfPPNdOnSpdz2Vq1a8ac//YkvvviC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DBaLpdwjKirK082qtRUrVjB8+HBiYmKwWCx88skn5d43DINnnnmGmJgY/P39GTRoEFu2bPFMY2vhXOc5bty4Ctf3wgsv9Exja2jatGn07t2b4OBgIiIiuP7669m+fXu5fRrD9azOeTb06zlz5ky6detWVgirX79+fPnll2XvN4brCOc+z4Z+Hasybdo0LBYLEydOLNvmymvaZMPIggULmDhxIk888QQbN25kwIABDBs2jJSUFE83zaXOP/98UlNTyx6bN2/2dJNqLTc3l+7du/PKK69U+v7zzz/Piy++yCuvvMK6deuIiori8ssvL1vjqKE413kCXHnlleWu7+LFi+uwhbW3fPly7r//ftauXcvSpUspKSlh6NCh5Obmlu3TGK5ndc4TGvb1jIuL47nnnmP9+vWsX7+ewYMHc91115X9cmoM1xHOfZ7QsK9jZdatW8cbb7xBt27dym136TU1mqg+ffoYEyZMKLetU6dOxuOPP+6hFrne008/bXTv3t3TzXArwPj444/LXjscDiMqKsp47rnnyrYVFBQYoaGhxmuvveaBFrrGmedpGIYxduxY47rrrvNIe9wlPT3dAIzly5cbhtF4r+eZ52kYjfN6hoeHG2+++WajvY6lSs/TMBrfdczOzjbat29vLF261LjkkkuMhx56yDAM1/+/2SR7RoqKitiwYQNDhw4tt33o0KGsXr3aQ61yj507dxITE0NiYiK33XYbe/bs8XST3Co5OZm0tLRy19bX15dLLrmk0V1bgGXLlhEREUGHDh343e9+R3p6uqebVCuZmZkANGvWDGi81/PM8yzVWK6n3W7n/fffJzc3l379+jXa63jmeZZqLNcR4P777+fqq6/msssuK7fd1de0QSyU52oZGRnY7XYiIyPLbY+MjCQtLc1DrXK9vn37Mm/ePDp06MDhw4eZOnUq/fv3Z8uWLTRv3tzTzXOL0utX2bXdt2+fJ5rkNsOGDeOWW26hVatWJCcn8+STTzJ48GA2bNjQICtAGobBpEmTuPjii+nSpQvQOK9nZecJjeN6bt68mX79+lFQUEBQUBAff/wx5513Xtkvp8ZyHas6T2gc17HU+++/z08//cS6desqvOfq/zebZBgpZbFYyr02DKPCtoZs2LBhZc+7du1Kv379aNu2LW+99RaTJk3yYMvcr7FfW4ARI0aUPe/SpQu9evWiVatWfPHFF9x4440ebFnNPPDAA/zyyy+sWrWqwnuN6XpWdZ6N4Xp27NiRTZs2ceLECT766CPGjh3L8uXLy95vLNexqvM877zzGsV1BNi/fz8PPfQQX3/9NX5+flXu56pr2iRv07Ro0QKbzVahFyQ9Pb1CymtMAgMD6dq1Kzt37vR0U9ymdLZQU7u2ANHR0bRq1apBXt8//OEPfPbZZ3z33XfExcWVbW9s17Oq86xMQ7yePj4+tGvXjl69ejFt2jS6d+/Oyy+/3OiuY1XnWZmGeB0BNmzYQHp6OklJSXh5eeHl5cXy5cv517/+hZeXV9l1c9U1bZJhxMfHh6SkJJYuXVpu+9KlS+nfv7+HWuV+hYWFbNu2jejoaE83xW0SExOJiooqd22LiopYvnx5o762AEePHmX//v0N6voahsEDDzzAokWL+Pbbb0lMTCz3fmO5nuc6z8o0xOt5JsMwKCwsbDTXsSql51mZhnodhwwZwubNm9m0aVPZo1evXowaNYpNmzbRpk0b117TWg2zbcDef/99w9vb25g1a5axdetWY+LEiUZgYKCxd+9eTzfNZR5++GFj2bJlxp49e4y1a9ca11xzjREcHNzgzzE7O9vYuHGjsXHjRgMwXnzxRWPjxo3Gvn37DMMwjOeee84IDQ01Fi1aZGzevNkYOXKkER0dbWRlZXm45c4523lmZ2cbDz/8sLF69WojOTnZ+O6774x+/foZsbGxDeo877vvPiM0NNRYtmyZkZqaWvbIy8sr26cxXM9znWdjuJ6TJ082VqxYYSQnJxu//PKL8ec//9mwWq3G119/bRhG47iOhnH282wM1/FsTp9NYxiuvaZNNowYhmG8+uqrRqtWrQwfHx+jZ8+e5abZNQYjRowwoqOjDW9vbyMmJsa48cYbjS1btni6WbX23XffGUCFx9ixYw3DMKecPf3000ZUVJTh6+trDBw40Ni8ebNnG10DZzvPvLw8Y+jQoUbLli0Nb29vIyEhwRg7dqyRkpLi6WY7pbLzA4w5c+aU7dMYrue5zrMxXM/x48eX/X3asmVLY8iQIWVBxDAax3U0jLOfZ2O4jmdzZhhx5TW1GIZh1KAHR0RERMQlmuSYEREREak/FEZERETEoxRGRERExKMURkRERMSjFEZERETEoxRGRERExKMURkRERMSjFEZERETEoxRGRERExKMURkRERMSjFEZERETEoxRGRERExKP+H8j5hNDL4HCGAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "metrics = pd.read_csv(\"logs/M3GNet_training/version_0/metrics.csv\")\n", + "metrics[\"train_MAE\"].dropna().plot()\n", + "metrics[\"val_MAE\"].dropna().plot()\n", + "\n", + "_ = plt.legend()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ddc98266", + "metadata": {}, + "outputs": [], + "source": [ + "# This code just performs cleanup for this notebook.\n", + "\n", + "for fn in (\"dgl_graph.bin\", \"dgl_line_graph.bin\", \"state_attr.pt\", \"labels.json\"):\n", + " try:\n", + " os.remove(fn)\n", + " except FileNotFoundError:\n", + " pass\n", + "\n", + "shutil.rmtree(\"logs\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb index b1e6175c..3cc4d17d 100644 --- a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb +++ b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb @@ -161,7 +161,7 @@ " element_types=element_types,\n", " is_intensive=False,\n", ")\n", - "lit_module = PotentialLightningModule(model=model)\n" + "lit_module = PotentialLightningModule(model=model)" ] }, {