From ccad860bedf71fa3026ee5eb7be18bae2d8a3450 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Mon, 28 Aug 2023 17:21:18 -0700 Subject: [PATCH 01/11] Optimize the Atoms2Graph and fixed the np.meshgrid --- matgl/ext/ase.py | 7 +++++-- matgl/graph/compute.py | 2 +- matgl/graph/converters.py | 17 +++++++++++------ matgl/utils/maths.py | 4 +++- tests/ext/test_ase.py | 14 ++++++++++++++ 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/matgl/ext/ase.py b/matgl/ext/ase.py index f06ab202..df440ebd 100644 --- a/matgl/ext/ase.py +++ b/matgl/ext/ase.py @@ -15,6 +15,8 @@ import pandas as pd import scipy.sparse as sp import torch +import matgl + from ase import Atoms, units from ase.calculators.calculator import Calculator, all_changes from ase.constraints import ExpCellFilter @@ -107,15 +109,16 @@ def get_graph(self, atoms: Atoms) -> tuple[dgl.DGLGraph, list]: src_id = adj.row dst_id = adj.col g, state_attr = super().get_graph_from_processed_structure( - AseAtomsAdaptor().get_structure(atoms) if atoms.pbc.all() else AseAtomsAdaptor().get_molecule(atoms), + atoms, src_id, dst_id, images if atoms.pbc.all() else np.zeros((len(adj.row), 3)), [lattice_matrix] if atoms.pbc.all() else lattice_matrix, element_types, cart_coords, + is_atoms=True, ) - g.ndata["volume"] = torch.tensor([volume] * g.num_nodes()) + g.ndata["volume"] = torch.tensor([volume] * g.num_nodes(), dtype=matgl.float_th) return g, state_attr diff --git a/matgl/graph/compute.py b/matgl/graph/compute.py index b3d29142..b878ad51 100644 --- a/matgl/graph/compute.py +++ b/matgl/graph/compute.py @@ -45,7 +45,7 @@ def compute_3body(g: dgl.DGLGraph): ``` """ r = np.arange(n) - x, y = np.meshgrid(r, r, indexing="ij") + x, y = np.meshgrid(r, r, indexing="xy") c = np.stack([y.ravel(), x.ravel()], axis=1) final = c[c[:, 0] != c[:, 1]] triple_bond_indices[start : start + (n * (n - 1)), :] = final + cs diff --git a/matgl/graph/converters.py b/matgl/graph/converters.py index c0adf954..52c163e9 100644 --- a/matgl/graph/converters.py +++ b/matgl/graph/converters.py @@ -31,6 +31,7 @@ def get_graph_from_processed_structure( lattice_matrix, element_types, cart_coords, + is_atoms: bool = False, ) -> tuple[dgl.DGLGraph, list]: """Construct a dgl graph from processed structure and bond information. @@ -42,7 +43,7 @@ def get_graph_from_processed_structure( lattice_matrix: lattice information of the structure. element_types: Element symbols of all atoms in the structure. cart_coords: Cartisian coordinates of all atoms in the structure. - + is_atoms: whether the input structure object is ASE atoms object or not. Returns: DGLGraph object, state_attr @@ -51,11 +52,15 @@ def get_graph_from_processed_structure( g = dgl.graph((u, v), num_nodes=len(structure)) pbc_offset = torch.tensor(images) g.edata["pbc_offset"] = pbc_offset.to(matgl.int_th) - g.edata["pbc_offshift"] = torch.matmul(pbc_offset, torch.tensor(lattice_matrix[0])) + g.edata["pbc_offshift"] = torch.matmul(pbc_offset, torch.tensor(lattice_matrix[0])).to(matgl.float_th) g.edata["lattice"] = torch.tensor(np.repeat(lattice_matrix, g.num_edges(), axis=0), dtype=matgl.float_th) - g.ndata["node_type"] = torch.tensor( - np.hstack([[element_types.index(site.specie.symbol)] for site in structure]), dtype=matgl.int_th + element_to_index = {elem: idx for idx, elem in enumerate(element_types)} + node_type = ( + np.array([element_types.index(site.specie.symbol) for site in structure]) + if is_atoms is False + else np.array([element_to_index[elem] for elem in structure.get_chemical_symbols()]) ) - g.ndata["pos"] = torch.tensor(cart_coords) - state_attr = [0.0, 0.0] + g.ndata["node_type"] = torch.tensor(node_type, dtype=matgl.int_th) + g.ndata["pos"] = torch.tensor(cart_coords, dtype=matgl.float_th) + state_attr = np.array([0.0, 0.0]).astype(matgl.float_np) return g, state_attr diff --git a/matgl/utils/maths.py b/matgl/utils/maths.py index e229db68..bee8d79c 100644 --- a/matgl/utils/maths.py +++ b/matgl/utils/maths.py @@ -9,6 +9,8 @@ import numpy as np import sympy import torch +import matgl + from scipy.optimize import brentq from scipy.special import spherical_jn @@ -16,7 +18,7 @@ # Precomputed Spherical Bessel function roots in a 2D array with dimension [128, 128]. The n-th (0-based index) root of # order l Spherical Bessel function is the `[l, n]` entry. -SPHERICAL_BESSEL_ROOTS = torch.tensor(np.load(os.path.join(CWD, "sb_roots.npy"))) +SPHERICAL_BESSEL_ROOTS = torch.tensor(np.load(os.path.join(CWD, "sb_roots.npy")), dtype=matgl.float_th) @lru_cache(maxsize=128) diff --git a/tests/ext/test_ase.py b/tests/ext/test_ase.py index fe6d2b49..1200193d 100644 --- a/tests/ext/test_ase.py +++ b/tests/ext/test_ase.py @@ -65,6 +65,20 @@ def test_get_graph_from_atoms(LiFePO4): # check the state features assert np.allclose(state, [0.0, 0.0]) +def test_get_graph_from_atoms_mol(): + mol = molecule("CH4") + a2g = Atoms2Graph(element_types=["H", "C"], cutoff=4.0) + graph, state = a2g.get_graph(mol) + # check the number of nodes + assert np.allclose(graph.num_nodes(), len(mol.get_atomic_numbers())) + # check the atomic feature of atom 0 + assert np.allclose(graph.ndata["node_type"].detach().numpy()[0], 1) + # check the atomic feature of atom 4 + assert np.allclose(graph.ndata["node_type"].detach().numpy()[1], 0) + # check the number of bonds + assert np.allclose(graph.num_edges(), 20) + # check the state features + assert np.allclose(state, [0.0, 0.0]) def test_molecular_dynamics(MoS): pot = load_model("M3GNet-MP-2021.2.8-PES") From bafbc166a58ba4add8cbbdccf6439a2362cfd4cb Mon Sep 17 00:00:00 2001 From: kenko911 Date: Mon, 28 Aug 2023 19:56:09 -0700 Subject: [PATCH 02/11] put unittests --- ...Net Potential with PyTorch Lightning.ipynb | 3306 +++-------------- matgl/ext/ase.py | 3 +- matgl/graph/converters.py | 1 + matgl/utils/maths.py | 4 +- tests/conftest.py | 100 + tests/ext/test_ase.py | 13 +- tests/graph/test_compute.py | 9 + 7 files changed, 571 insertions(+), 2865 deletions(-) diff --git a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb index 1b301aaa..1f899118 100644 --- a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb +++ b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb @@ -1,2881 +1,475 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "35c97a76", - "metadata": { - "id": "35c97a76" - }, - "source": [ - "# Introduction\n", - "\n", - "This notebook demonstrates how to fit a M3GNet potential using PyTorch Lightning with MatGL." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6355190a", - "metadata": { - "id": "6355190a" - }, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import os\n", - "import shutil\n", - "import warnings\n", - "\n", - "import numpy as np\n", - "import pytorch_lightning as pl\n", - "from dgl.data.utils import split_dataset\n", - "from mp_api.client import MPRester\n", - "from pytorch_lightning.loggers import CSVLogger\n", - "\n", - "import matgl\n", - "from matgl.ext.pymatgen import Structure2Graph, get_element_list\n", - "from matgl.graph.data import M3GNetDataset, MGLDataLoader, collate_fn_efs\n", - "from matgl.models import M3GNet\n", - "from matgl.utils.training import PotentialLightningModule\n", - "\n", - "# To suppress warnings for clearer output\n", - "warnings.simplefilter(\"ignore\")" - ] - }, - { - "cell_type": "markdown", - "id": "eaafc0bd", - "metadata": { - "id": "eaafc0bd" - }, - "source": [ - "For the purposes of demonstration, we will download all Si-O compounds in the Materials Project via the MPRester. The forces and stresses are set to zero, though in a real context, these would be non-zero and obtained from DFT calculations." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "bd0ce8a2-ec68-4160-9457-823fb9e6a35d", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 67, - "referenced_widgets": [ - "aac9f06228444b8dbd7dd798e6c1a93f", - "591a338fe6304870bebd845eb8d8e2a9", - "19fe8f71e71048bf9a923291ad9b1bb4", - "0ab337e54e0943cb8bc940922fb425f5", - "ed3ba68de443454b8be182c1901f8cfa", - "a93bf23e7f224a3092094a1b0961251a", - "a5503afc1d2b427d9fd0e83bf733387d", - "fbad168bdfc34eb1a439bc3334748369", - "4deece8c90b249f384722bce145a6a08", - "d2777074f8d148c591652654e68e6d9f", - "2eda31d46a5d440281571f3ea1240228" - ] - }, - "id": "bd0ce8a2-ec68-4160-9457-823fb9e6a35d", - "outputId": "2252a59c-9a70-4673-926f-9ed8fc69ed0d" - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Retrieving ThermoDoc documents: 100%|██████████| 407/407 [00:00<00:00, 4962446.88it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "407 downloaded from MP.\n" - ] - } - ], - "source": [ - "# Obtain your API key here: https://next-gen.materialsproject.org/api\n", - "mpr = MPRester(api_key=\"YOUR_API_KEY\")\n", - "\n", - "entries = mpr.get_entries_in_chemsys([\"Si\", \"O\"])\n", - "structures = [e.structure for e in entries]\n", - "energies = [e.energy for e in entries]\n", - "forces = [np.zeros((len(s), 3)).tolist() for s in structures]\n", - "stresses = [np.zeros((3, 3)).tolist() for s in structures]\n", - "labels = {\n", - " \"energies\": energies,\n", - " \"forces\": forces,\n", - " \"stresses\": stresses,\n", - "}\n", - "\n", - "print(f\"{len(structures)} downloaded from MP.\")" - ] + "cells": [ + { + "cell_type": "markdown", + "id": "35c97a76", + "metadata": { + "id": "35c97a76" + }, + "source": [ + "# Introduction\n", + "\n", + "This notebook demonstrates how to fit a M3GNet potential using PyTorch Lightning with MatGL." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6355190a", + "metadata": { + "id": "6355190a" + }, + "outputs": [], + "source": [ + "from __future__ import annotations\n", + "\n", + "import os\n", + "import shutil\n", + "import warnings\n", + "\n", + "import numpy as np\n", + "import pytorch_lightning as pl\n", + "from dgl.data.utils import split_dataset\n", + "from mp_api.client import MPRester\n", + "from pytorch_lightning.loggers import CSVLogger\n", + "\n", + "import matgl\n", + "from matgl.ext.pymatgen import Structure2Graph, get_element_list\n", + "from matgl.graph.data import M3GNetDataset, MGLDataLoader, collate_fn_efs\n", + "from matgl.models import M3GNet\n", + "from matgl.utils.training import PotentialLightningModule\n", + "\n", + "# To suppress warnings for clearer output\n", + "warnings.simplefilter(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "id": "eaafc0bd", + "metadata": { + "id": "eaafc0bd" + }, + "source": [ + "For the purposes of demonstration, we will download all Si-O compounds in the Materials Project via the MPRester. The forces and stresses are set to zero, though in a real context, these would be non-zero and obtained from DFT calculations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bd0ce8a2-ec68-4160-9457-823fb9e6a35d", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 67, + "referenced_widgets": [ + "aac9f06228444b8dbd7dd798e6c1a93f", + "591a338fe6304870bebd845eb8d8e2a9", + "19fe8f71e71048bf9a923291ad9b1bb4", + "0ab337e54e0943cb8bc940922fb425f5", + "ed3ba68de443454b8be182c1901f8cfa", + "a93bf23e7f224a3092094a1b0961251a", + "a5503afc1d2b427d9fd0e83bf733387d", + "fbad168bdfc34eb1a439bc3334748369", + "4deece8c90b249f384722bce145a6a08", + "d2777074f8d148c591652654e68e6d9f", + "2eda31d46a5d440281571f3ea1240228" + ] }, + "id": "bd0ce8a2-ec68-4160-9457-823fb9e6a35d", + "outputId": "2252a59c-9a70-4673-926f-9ed8fc69ed0d" + }, + "outputs": [ { - "cell_type": "markdown", - "id": "f666cb23", - "metadata": { - "id": "f666cb23" - }, - "source": [ - "We will first setup the M3GNet model and the LightningModule." - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "Retrieving ThermoDoc documents: 100%|██████████| 407/407 [00:00<00:00, 4962446.88it/s]\n" + ] }, { - "cell_type": "code", - "execution_count": 3, - "id": "e9dc84cb", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "e9dc84cb", - "outputId": "b9f93f24-0fd6-4737-a8e4-e87804cd3ad2" - }, - "outputs": [], - "source": [ - "element_types = get_element_list(structures)\n", - "converter = Structure2Graph(element_types=element_types, cutoff=5.0)\n", - "dataset = M3GNetDataset(\n", - " threebody_cutoff=4.0,\n", - " structures=structures,\n", - " converter=converter,\n", - " labels=labels,\n", - ")\n", - "train_data, val_data, test_data = split_dataset(\n", - " dataset,\n", - " frac_list=[0.8, 0.1, 0.1],\n", - " shuffle=True,\n", - " random_state=42,\n", - ")\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=collate_fn_efs,\n", - " batch_size=2,\n", - " num_workers=1,\n", - ")\n", - "model = M3GNet(\n", - " element_types=element_types,\n", - " is_intensive=False,\n", - ")\n", - "lit_module = PotentialLightningModule(model=model)\n" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "407 downloaded from MP.\n" + ] + } + ], + "source": [ + "# Obtain your API key here: https://next-gen.materialsproject.org/api\n", + "mpr = MPRester(api_key=\"YOUR_API_KEY\")\n", + "\n", + "entries = mpr.get_entries_in_chemsys([\"Si\", \"O\"])\n", + "structures = [e.structure for e in entries]\n", + "energies = [e.energy for e in entries]\n", + "forces = [np.zeros((len(s), 3)).tolist() for s in structures]\n", + "stresses = [np.zeros((3, 3)).tolist() for s in structures]\n", + "labels = {\n", + " \"energies\": energies,\n", + " \"forces\": forces,\n", + " \"stresses\": stresses,\n", + "}\n", + "\n", + "print(f\"{len(structures)} downloaded from MP.\")" + ] + }, + { + "cell_type": "markdown", + "id": "f666cb23", + "metadata": { + "id": "f666cb23" + }, + "source": [ + "We will first setup the M3GNet model and the LightningModule." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9dc84cb", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, - { - "cell_type": "markdown", - "id": "01be4689", - "metadata": { - "id": "01be4689" - }, - "source": [ - "Finally, we will initialize the Pytorch Lightning trainer and run the fitting. Here, the max_epochs is set to 2 just for demonstration purposes. In a real fitting, this would be a much larger number. Also, 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." - ] + "id": "e9dc84cb", + "outputId": "b9f93f24-0fd6-4737-a8e4-e87804cd3ad2" + }, + "outputs": [], + "source": [ + "element_types = get_element_list(structures)\n", + "converter = Structure2Graph(element_types=element_types, cutoff=5.0)\n", + "dataset = M3GNetDataset(\n", + " threebody_cutoff=4.0,\n", + " structures=structures,\n", + " converter=converter,\n", + " labels=labels,\n", + ")\n", + "train_data, val_data, test_data = split_dataset(\n", + " dataset,\n", + " frac_list=[0.8, 0.1, 0.1],\n", + " shuffle=True,\n", + " random_state=42,\n", + ")\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=collate_fn_efs,\n", + " batch_size=2,\n", + " num_workers=1,\n", + ")\n", + "model = M3GNet(\n", + " element_types=element_types,\n", + " is_intensive=False,\n", + ")\n", + "lit_module = PotentialLightningModule(model=model)\n" + ] + }, + { + "cell_type": "markdown", + "id": "01be4689", + "metadata": { + "id": "01be4689" + }, + "source": [ + "Finally, we will initialize the Pytorch Lightning trainer and run the fitting. Here, the max_epochs is set to 2 just for demonstration purposes. In a real fitting, this would be a much larger number. Also, 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." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7472d071", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 423, + "referenced_widgets": [ + "ca0304013c864637b614ca03d131f920", + "e6d2aa7fa6d644f39fa9eefaabbbef48", + "cbaf8681aaa1410d9150f70f755628af", + "f4b8c28792544919b47bc832cd93d4a6", + "9d73d246aa1a47a9af3d1e2caa961b5d", + "c6dc5ee98e1346a08067491930872eff", + "2a89da23f17c4b0b85ce81bcfd69cc37", + "5161471448ae4ec1b8ba2d2152f42153", + "641cc028432f453a8ef3eeab201a9218", + "f562f5b7289d4fcf9f310426aa620521", + "3b95d47d64994a9eb812488ddbac61ec", + "4ce50de72a8a4b5f995e72487f34c560", + "f4ec778fed4749e890cdac57ef0a16f5", + "daaabf9a40b64db6a2240f7e2ae27d08", + "bb84fc3ffb3a4add91ce6af226f9c4af", + "b32866d1699a46fe814e42ef2e5b8477", + "bd3cb443099643b194a13b5cd3ad037f", + "f7b6a5d231bc45c98c7eec9e40c5943c", + "79e719731a74439da8bff2cc57c9898e", + "1b2cc76759ce4164b28d407911590d73", + "ac65110f92bc494d843ef347c980031f", + "0c466ca4cfb34eb58db798b750fecfaa", + "67f78887930f4ba8a9ad25035ab48801", + "ea74e30a47d043c991770a3d82aadbb5", + "56949107dcd94055bc6115404a0de63f", + "9f6d6018de5a42afbfca719fa7b2a740", + "2b8242683dd54bf9aa82e3e186fde7c5", + "b3359b9ef6384c0cae5849f0b80d6cb1", + "169f8ac55aa14dc393b5381e56783dc5", + "53be090dca604f3c98e944bcfb35e34d", + "9de7ce8be6ea4f5298870cc326895412", + "1ee31acfe8dd4002a3917561f83b91bd", + "bf983f21b4b34030b9c14e912a8d5450" + ] }, + "id": "7472d071", + "outputId": "9d10c152-752f-4afc-8759-c5174ea446b9" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 4, - "id": "7472d071", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 423, - "referenced_widgets": [ - "ca0304013c864637b614ca03d131f920", - "e6d2aa7fa6d644f39fa9eefaabbbef48", - "cbaf8681aaa1410d9150f70f755628af", - "f4b8c28792544919b47bc832cd93d4a6", - "9d73d246aa1a47a9af3d1e2caa961b5d", - "c6dc5ee98e1346a08067491930872eff", - "2a89da23f17c4b0b85ce81bcfd69cc37", - "5161471448ae4ec1b8ba2d2152f42153", - "641cc028432f453a8ef3eeab201a9218", - "f562f5b7289d4fcf9f310426aa620521", - "3b95d47d64994a9eb812488ddbac61ec", - "4ce50de72a8a4b5f995e72487f34c560", - "f4ec778fed4749e890cdac57ef0a16f5", - "daaabf9a40b64db6a2240f7e2ae27d08", - "bb84fc3ffb3a4add91ce6af226f9c4af", - "b32866d1699a46fe814e42ef2e5b8477", - "bd3cb443099643b194a13b5cd3ad037f", - "f7b6a5d231bc45c98c7eec9e40c5943c", - "79e719731a74439da8bff2cc57c9898e", - "1b2cc76759ce4164b28d407911590d73", - "ac65110f92bc494d843ef347c980031f", - "0c466ca4cfb34eb58db798b750fecfaa", - "67f78887930f4ba8a9ad25035ab48801", - "ea74e30a47d043c991770a3d82aadbb5", - "56949107dcd94055bc6115404a0de63f", - "9f6d6018de5a42afbfca719fa7b2a740", - "2b8242683dd54bf9aa82e3e186fde7c5", - "b3359b9ef6384c0cae5849f0b80d6cb1", - "169f8ac55aa14dc393b5381e56783dc5", - "53be090dca604f3c98e944bcfb35e34d", - "9de7ce8be6ea4f5298870cc326895412", - "1ee31acfe8dd4002a3917561f83b91bd", - "bf983f21b4b34030b9c14e912a8d5450" - ] - }, - "id": "7472d071", - "outputId": "9d10c152-752f-4afc-8759-c5174ea446b9" - }, - "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 | mae | MeanAbsoluteError | 0 \n", - "1 | rmse | MeanSquaredError | 0 \n", - "2 | model | Potential | 282 K \n", - "--------------------------------------------\n", - "282 K Trainable params\n", - "0 Non-trainable params\n", - "282 K Total params\n", - "1.130 Total estimated model params size (MB)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 0: 100%|██████████| 163/163 [00:39<00:00, 4.16it/s, v_num=1, val_Total_Loss=0.815, val_Energy_MAE=0.674, val_Force_MAE=0.289, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=0.730, val_Force_RMSE=0.419, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.60, train_Energy_MAE=2.500, train_Force_MAE=0.349, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=2.660, train_Force_RMSE=0.487, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "`Trainer.fit` stopped: `max_epochs=1` reached.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 0: 100%|██████████| 163/163 [00:40<00:00, 3.99it/s, v_num=1, val_Total_Loss=0.815, val_Energy_MAE=0.674, val_Force_MAE=0.289, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=0.730, val_Force_RMSE=0.419, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.60, train_Energy_MAE=2.500, train_Force_MAE=0.349, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=2.660, train_Force_RMSE=0.487, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]\n" - ] - } - ], - "source": [ - "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", - "logger = CSVLogger(\"logs\", name=\"M3GNet_training\")\n", - "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", - "trainer.fit(model=lit_module, train_dataloaders=train_loader, val_dataloaders=val_loader)" - ] + "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 | mae | MeanAbsoluteError | 0 \n", + "1 | rmse | MeanSquaredError | 0 \n", + "2 | model | Potential | 282 K \n", + "--------------------------------------------\n", + "282 K Trainable params\n", + "0 Non-trainable params\n", + "282 K Total params\n", + "1.130 Total estimated model params size (MB)\n" + ] }, { - "cell_type": "code", - "execution_count": 5, - "id": "e9f0202f", - "metadata": {}, - "outputs": [], - "source": [ - "# save trained model\n", - "model_export_path = \"./trained_model/\"\n", - "model.save(model_export_path)\n", - "\n", - "# load trained model\n", - "model = matgl.load_model(path = model_export_path)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: 100%|██████████| 163/163 [00:39<00:00, 4.16it/s, v_num=1, val_Total_Loss=0.815, val_Energy_MAE=0.674, val_Force_MAE=0.289, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=0.730, val_Force_RMSE=0.419, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.60, train_Energy_MAE=2.500, train_Force_MAE=0.349, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=2.660, train_Force_RMSE=0.487, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" + ] }, { - "cell_type": "markdown", - "id": "e14a229a", - "metadata": {}, - "source": [ - "## Finetuning a pre-trained M3GNet\n", - "In the previous cells, we demonstrated the process of training an M3GNet from scratch. Next, let's see how to perform additional training on an M3GNet that has already been trained using Materials Project data." - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] }, { - "cell_type": "code", - "execution_count": 6, - "id": "85ef3a34-e6fb-452b-82cc-65012e80bce6", - "metadata": { - "id": "85ef3a34-e6fb-452b-82cc-65012e80bce6" - }, - "outputs": [], - "source": [ - "# download a pre-trained M3GNet\n", - "m3gnet_nnp = matgl.load_model(\"M3GNet-MP-2021.2.8-PES\")\n", - "model_pretrained = m3gnet_nnp.model\n", - "lit_module_finetune = PotentialLightningModule(model=model_pretrained, lr=1e-4)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: 100%|██████████| 163/163 [00:40<00:00, 3.99it/s, v_num=1, val_Total_Loss=0.815, val_Energy_MAE=0.674, val_Force_MAE=0.289, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=0.730, val_Force_RMSE=0.419, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.60, train_Energy_MAE=2.500, train_Force_MAE=0.349, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=2.660, train_Force_RMSE=0.487, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]\n" + ] + } + ], + "source": [ + "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", + "logger = CSVLogger(\"logs\", name=\"M3GNet_training\")\n", + "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", + "trainer.fit(model=lit_module, train_dataloaders=train_loader, val_dataloaders=val_loader)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9f0202f", + "metadata": {}, + "outputs": [], + "source": [ + "# save trained model\n", + "model_export_path = \"./trained_model/\"\n", + "model.save(model_export_path)\n", + "\n", + "# load trained model\n", + "model = matgl.load_model(path = model_export_path)" + ] + }, + { + "cell_type": "markdown", + "id": "e14a229a", + "metadata": {}, + "source": [ + "## Finetuning a pre-trained M3GNet\n", + "In the previous cells, we demonstrated the process of training an M3GNet from scratch. Next, let's see how to perform additional training on an M3GNet that has already been trained using Materials Project data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "85ef3a34-e6fb-452b-82cc-65012e80bce6", + "metadata": { + "id": "85ef3a34-e6fb-452b-82cc-65012e80bce6" + }, + "outputs": [], + "source": [ + "# download a pre-trained M3GNet\n", + "m3gnet_nnp = matgl.load_model(\"M3GNet-MP-2021.2.8-PES\")\n", + "model_pretrained = m3gnet_nnp.model\n", + "lit_module_finetune = PotentialLightningModule(model=model_pretrained, lr=1e-4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4133225a-5990-4b97-9d73-88195df87a1a", + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 423, + "referenced_widgets": [ + "9d537bceb5994f0ca8908e6a8fa8dda0", + "783e4a0f711e4e63b68bdfead3dd29dd", + "b835f08350de4bfab6ce0e06b15c0e01", + "ee3af67a2be244988ca27a46472f18c5", + "30631c73610d4438a894a676ed31e49a", + "ac1633b9d785471098cb40db339edb3f", + "dfcaa58a05ab49a0b82108f04984e48b", + "a8318cebd921434caee81d717a5f01fa", + "479321dba45e48648bba9bad86ad4c4c", + "8ac7f6294ff949b1a10da96532387ebb", + "edafb607f21045d98a4b0c2059d27958", + "d23643bb47234c969df66ad2ad223b4f", + "fac4d3e8a6b64524bb0aa08036aa0588", + "20ccc55a5b264bc3b193d324caeae685", + "44f14d0ce3af41f5bb8f048a69da6a5d", + "e8f06e2730cf4aef8427932a033252ab", + "b662754e5b484ea58433fef79d401ce6", + "4977216b2e9f4e94a41520127fde4a03", + "c62f28b519c04081831d1a2507003e38", + "e23184852e70488698cc75272c7057ae", + "b7e24728fbb444c39a7115988c289883", + "6921ddc707334f5d99b13e519d10d437", + "db8cc5bcec1d4d0b999b48eb7a36f0de", + "12511f8f4b134a7f80feada2b65240d0", + "34a896f642fa47a78fe858ba8ab95c9e", + "3a43080c70054e7793e73b5d49e48448", + "88dddbd1837c4bfbbb1870beb73aa08a", + "c59c41ae3d224b5aaa888a7526e1a130", + "9cb7a81f00dc4d97b3f0639ec6dde1a4", + "dba16d8574f8475f9d8f973fbf968b59", + "d4df21b4ef1a4d3b938c5657337b7ec1", + "b6a3965a166940d289ab4a50f2e78a60", + "b5813fa692a74bf2aec3fbdf03088f3d" + ] }, + "id": "4133225a-5990-4b97-9d73-88195df87a1a", + "outputId": "f149a68a-eef7-4726-b3a1-723525dc908f" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 7, - "id": "4133225a-5990-4b97-9d73-88195df87a1a", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 423, - "referenced_widgets": [ - "9d537bceb5994f0ca8908e6a8fa8dda0", - "783e4a0f711e4e63b68bdfead3dd29dd", - "b835f08350de4bfab6ce0e06b15c0e01", - "ee3af67a2be244988ca27a46472f18c5", - "30631c73610d4438a894a676ed31e49a", - "ac1633b9d785471098cb40db339edb3f", - "dfcaa58a05ab49a0b82108f04984e48b", - "a8318cebd921434caee81d717a5f01fa", - "479321dba45e48648bba9bad86ad4c4c", - "8ac7f6294ff949b1a10da96532387ebb", - "edafb607f21045d98a4b0c2059d27958", - "d23643bb47234c969df66ad2ad223b4f", - "fac4d3e8a6b64524bb0aa08036aa0588", - "20ccc55a5b264bc3b193d324caeae685", - "44f14d0ce3af41f5bb8f048a69da6a5d", - "e8f06e2730cf4aef8427932a033252ab", - "b662754e5b484ea58433fef79d401ce6", - "4977216b2e9f4e94a41520127fde4a03", - "c62f28b519c04081831d1a2507003e38", - "e23184852e70488698cc75272c7057ae", - "b7e24728fbb444c39a7115988c289883", - "6921ddc707334f5d99b13e519d10d437", - "db8cc5bcec1d4d0b999b48eb7a36f0de", - "12511f8f4b134a7f80feada2b65240d0", - "34a896f642fa47a78fe858ba8ab95c9e", - "3a43080c70054e7793e73b5d49e48448", - "88dddbd1837c4bfbbb1870beb73aa08a", - "c59c41ae3d224b5aaa888a7526e1a130", - "9cb7a81f00dc4d97b3f0639ec6dde1a4", - "dba16d8574f8475f9d8f973fbf968b59", - "d4df21b4ef1a4d3b938c5657337b7ec1", - "b6a3965a166940d289ab4a50f2e78a60", - "b5813fa692a74bf2aec3fbdf03088f3d" - ] - }, - "id": "4133225a-5990-4b97-9d73-88195df87a1a", - "outputId": "f149a68a-eef7-4726-b3a1-723525dc908f" - }, - "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 | mae | MeanAbsoluteError | 0 \n", - "1 | rmse | MeanSquaredError | 0 \n", - "2 | model | Potential | 288 K \n", - "--------------------------------------------\n", - "288 K Trainable params\n", - "0 Non-trainable params\n", - "288 K Total params\n", - "1.153 Total estimated model params size (MB)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 0: 100%|██████████| 163/163 [00:37<00:00, 4.34it/s, v_num=1, val_Total_Loss=5.420, val_Energy_MAE=1.070, val_Force_MAE=0.407, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=1.330, val_Force_RMSE=0.615, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.80, train_Energy_MAE=3.270, train_Force_MAE=0.572, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=3.430, train_Force_RMSE=0.870, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "`Trainer.fit` stopped: `max_epochs=1` reached.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 0: 100%|██████████| 163/163 [00:39<00:00, 4.17it/s, v_num=1, val_Total_Loss=5.420, val_Energy_MAE=1.070, val_Force_MAE=0.407, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=1.330, val_Force_RMSE=0.615, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.80, train_Energy_MAE=3.270, train_Force_MAE=0.572, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=3.430, train_Force_RMSE=0.870, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]\n" - ] - } - ], - "source": [ - "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", - "logger = CSVLogger(\"logs\", name=\"M3GNet_finetuning\")\n", - "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", - "trainer.fit(model=lit_module_finetune, train_dataloaders=train_loader, val_dataloaders=val_loader)" - ] + "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 | mae | MeanAbsoluteError | 0 \n", + "1 | rmse | MeanSquaredError | 0 \n", + "2 | model | Potential | 288 K \n", + "--------------------------------------------\n", + "288 K Trainable params\n", + "0 Non-trainable params\n", + "288 K Total params\n", + "1.153 Total estimated model params size (MB)\n" + ] }, { - "cell_type": "code", - "execution_count": 8, - "id": "252f6456-3ecf-47f0-84ca-c8e9dcc66ccc", - "metadata": { - "id": "252f6456-3ecf-47f0-84ca-c8e9dcc66ccc" - }, - "outputs": [], - "source": [ - "# save trained model\n", - "model_save_path = \"./finetuned_model/\"\n", - "model_pretrained.save(model_save_path)\n", - "# load trained model\n", - "trained_model = matgl.load_model(path = model_save_path)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: 100%|██████████| 163/163 [00:37<00:00, 4.34it/s, v_num=1, val_Total_Loss=5.420, val_Energy_MAE=1.070, val_Force_MAE=0.407, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=1.330, val_Force_RMSE=0.615, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.80, train_Energy_MAE=3.270, train_Force_MAE=0.572, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=3.430, train_Force_RMSE=0.870, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" + ] }, { - "cell_type": "code", - "execution_count": 9, - "id": "cd11b92f", - "metadata": { - "id": "cd11b92f" - }, - "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\")\n", - "shutil.rmtree(\"trained_model\")\n", - "shutil.rmtree(\"finetuned_model\")" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "`Trainer.fit` stopped: `max_epochs=1` reached.\n" + ] }, { - "cell_type": "code", - "execution_count": null, - "id": "bc4288f2", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "colab": { - "provenance": [] - }, - "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.4" - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "0ab337e54e0943cb8bc940922fb425f5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_d2777074f8d148c591652654e68e6d9f", - "placeholder": "​", - "style": "IPY_MODEL_2eda31d46a5d440281571f3ea1240228", - "value": " 407/407 [00:00<00:00, 22319.17it/s]" - } - }, - "0c466ca4cfb34eb58db798b750fecfaa": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "12511f8f4b134a7f80feada2b65240d0": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_c59c41ae3d224b5aaa888a7526e1a130", - "placeholder": "​", - "style": "IPY_MODEL_9cb7a81f00dc4d97b3f0639ec6dde1a4", - "value": "Validation DataLoader 0: 100%" - } - }, - "169f8ac55aa14dc393b5381e56783dc5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "19fe8f71e71048bf9a923291ad9b1bb4": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "success", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_fbad168bdfc34eb1a439bc3334748369", - "max": 407, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_4deece8c90b249f384722bce145a6a08", - "value": 407 - } - }, - "1b2cc76759ce4164b28d407911590d73": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "1ee31acfe8dd4002a3917561f83b91bd": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "20ccc55a5b264bc3b193d324caeae685": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "success", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_c62f28b519c04081831d1a2507003e38", - "max": 163, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_e23184852e70488698cc75272c7057ae", - "value": 163 - } - }, - "2a89da23f17c4b0b85ce81bcfd69cc37": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "2b8242683dd54bf9aa82e3e186fde7c5": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": "hidden", - "width": "100%" - } - }, - "2eda31d46a5d440281571f3ea1240228": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "30631c73610d4438a894a676ed31e49a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": "hidden", - "width": "100%" - } - }, - "34a896f642fa47a78fe858ba8ab95c9e": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_dba16d8574f8475f9d8f973fbf968b59", - "max": 20, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_d4df21b4ef1a4d3b938c5657337b7ec1", - "value": 20 - } - }, - "3a43080c70054e7793e73b5d49e48448": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_b6a3965a166940d289ab4a50f2e78a60", - "placeholder": "​", - "style": "IPY_MODEL_b5813fa692a74bf2aec3fbdf03088f3d", - "value": " 20/20 [00:08<00:00, 2.33it/s]" - } - }, - "3b95d47d64994a9eb812488ddbac61ec": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "44f14d0ce3af41f5bb8f048a69da6a5d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_b7e24728fbb444c39a7115988c289883", - "placeholder": "​", - "style": "IPY_MODEL_6921ddc707334f5d99b13e519d10d437", - "value": " 163/163 [02:15<00:00, 1.20it/s, v_num=0, val_Total_Loss=6.640, val_Energy_MAE=1.460, val_Force_MAE=0.626, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=1.670, val_Force_RMSE=0.951, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=22.60, train_Energy_MAE=3.300, train_Force_MAE=0.586, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=3.460, train_Force_RMSE=0.916, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" - } - }, - "479321dba45e48648bba9bad86ad4c4c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "4977216b2e9f4e94a41520127fde4a03": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "4ce50de72a8a4b5f995e72487f34c560": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_f4ec778fed4749e890cdac57ef0a16f5", - "IPY_MODEL_daaabf9a40b64db6a2240f7e2ae27d08", - "IPY_MODEL_bb84fc3ffb3a4add91ce6af226f9c4af" - ], - "layout": "IPY_MODEL_b32866d1699a46fe814e42ef2e5b8477" - } - }, - "4deece8c90b249f384722bce145a6a08": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "5161471448ae4ec1b8ba2d2152f42153": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "53be090dca604f3c98e944bcfb35e34d": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "56949107dcd94055bc6115404a0de63f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_53be090dca604f3c98e944bcfb35e34d", - "max": 20, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_9de7ce8be6ea4f5298870cc326895412", - "value": 20 - } - }, - "591a338fe6304870bebd845eb8d8e2a9": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_a93bf23e7f224a3092094a1b0961251a", - "placeholder": "​", - "style": "IPY_MODEL_a5503afc1d2b427d9fd0e83bf733387d", - "value": "Retrieving ThermoDoc documents: 100%" - } - }, - "641cc028432f453a8ef3eeab201a9218": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "67f78887930f4ba8a9ad25035ab48801": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_ea74e30a47d043c991770a3d82aadbb5", - "IPY_MODEL_56949107dcd94055bc6115404a0de63f", - "IPY_MODEL_9f6d6018de5a42afbfca719fa7b2a740" - ], - "layout": "IPY_MODEL_2b8242683dd54bf9aa82e3e186fde7c5" - } - }, - "6921ddc707334f5d99b13e519d10d437": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "783e4a0f711e4e63b68bdfead3dd29dd": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_ac1633b9d785471098cb40db339edb3f", - "placeholder": "​", - "style": "IPY_MODEL_dfcaa58a05ab49a0b82108f04984e48b", - "value": "Sanity Checking DataLoader 0: 100%" - } - }, - "79e719731a74439da8bff2cc57c9898e": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "88dddbd1837c4bfbbb1870beb73aa08a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": "hidden", - "width": "100%" - } - }, - "8ac7f6294ff949b1a10da96532387ebb": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "9cb7a81f00dc4d97b3f0639ec6dde1a4": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "9d537bceb5994f0ca8908e6a8fa8dda0": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_783e4a0f711e4e63b68bdfead3dd29dd", - "IPY_MODEL_b835f08350de4bfab6ce0e06b15c0e01", - "IPY_MODEL_ee3af67a2be244988ca27a46472f18c5" - ], - "layout": "IPY_MODEL_30631c73610d4438a894a676ed31e49a" - } - }, - "9d73d246aa1a47a9af3d1e2caa961b5d": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": "hidden", - "width": "100%" - } - }, - "9de7ce8be6ea4f5298870cc326895412": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "9f6d6018de5a42afbfca719fa7b2a740": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_1ee31acfe8dd4002a3917561f83b91bd", - "placeholder": "​", - "style": "IPY_MODEL_bf983f21b4b34030b9c14e912a8d5450", - "value": " 20/20 [00:06<00:00, 3.05it/s]" - } - }, - "a5503afc1d2b427d9fd0e83bf733387d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "a8318cebd921434caee81d717a5f01fa": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "a93bf23e7f224a3092094a1b0961251a": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "aac9f06228444b8dbd7dd798e6c1a93f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_591a338fe6304870bebd845eb8d8e2a9", - "IPY_MODEL_19fe8f71e71048bf9a923291ad9b1bb4", - "IPY_MODEL_0ab337e54e0943cb8bc940922fb425f5" - ], - "layout": "IPY_MODEL_ed3ba68de443454b8be182c1901f8cfa" - } - }, - "ac1633b9d785471098cb40db339edb3f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "ac65110f92bc494d843ef347c980031f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b32866d1699a46fe814e42ef2e5b8477": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": "100%" - } - }, - "b3359b9ef6384c0cae5849f0b80d6cb1": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b5813fa692a74bf2aec3fbdf03088f3d": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "b662754e5b484ea58433fef79d401ce6": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b6a3965a166940d289ab4a50f2e78a60": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b7e24728fbb444c39a7115988c289883": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "b835f08350de4bfab6ce0e06b15c0e01": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_a8318cebd921434caee81d717a5f01fa", - "max": 2, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_479321dba45e48648bba9bad86ad4c4c", - "value": 2 - } - }, - "bb84fc3ffb3a4add91ce6af226f9c4af": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_ac65110f92bc494d843ef347c980031f", - "placeholder": "​", - "style": "IPY_MODEL_0c466ca4cfb34eb58db798b750fecfaa", - "value": " 163/163 [02:18<00:00, 1.17it/s, v_num=0, val_Total_Loss=0.622, val_Energy_MAE=0.657, val_Force_MAE=0.225, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=0.679, val_Force_RMSE=0.321, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=7.990, train_Energy_MAE=1.700, train_Force_MAE=0.344, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=1.800, train_Force_RMSE=0.485, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]" - } - }, - "bd3cb443099643b194a13b5cd3ad037f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "bf983f21b4b34030b9c14e912a8d5450": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "c59c41ae3d224b5aaa888a7526e1a130": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "c62f28b519c04081831d1a2507003e38": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "c6dc5ee98e1346a08067491930872eff": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "ca0304013c864637b614ca03d131f920": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_e6d2aa7fa6d644f39fa9eefaabbbef48", - "IPY_MODEL_cbaf8681aaa1410d9150f70f755628af", - "IPY_MODEL_f4b8c28792544919b47bc832cd93d4a6" - ], - "layout": "IPY_MODEL_9d73d246aa1a47a9af3d1e2caa961b5d" - } - }, - "cbaf8681aaa1410d9150f70f755628af": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_5161471448ae4ec1b8ba2d2152f42153", - "max": 2, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_641cc028432f453a8ef3eeab201a9218", - "value": 2 - } - }, - "d23643bb47234c969df66ad2ad223b4f": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_fac4d3e8a6b64524bb0aa08036aa0588", - "IPY_MODEL_20ccc55a5b264bc3b193d324caeae685", - "IPY_MODEL_44f14d0ce3af41f5bb8f048a69da6a5d" - ], - "layout": "IPY_MODEL_e8f06e2730cf4aef8427932a033252ab" - } - }, - "d2777074f8d148c591652654e68e6d9f": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "d4df21b4ef1a4d3b938c5657337b7ec1": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "daaabf9a40b64db6a2240f7e2ae27d08": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "FloatProgressModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "FloatProgressModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ProgressView", - "bar_style": "success", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_79e719731a74439da8bff2cc57c9898e", - "max": 163, - "min": 0, - "orientation": "horizontal", - "style": "IPY_MODEL_1b2cc76759ce4164b28d407911590d73", - "value": 163 - } - }, - "db8cc5bcec1d4d0b999b48eb7a36f0de": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HBoxModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_12511f8f4b134a7f80feada2b65240d0", - "IPY_MODEL_34a896f642fa47a78fe858ba8ab95c9e", - "IPY_MODEL_3a43080c70054e7793e73b5d49e48448" - ], - "layout": "IPY_MODEL_88dddbd1837c4bfbbb1870beb73aa08a" - } - }, - "dba16d8574f8475f9d8f973fbf968b59": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": "2", - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "dfcaa58a05ab49a0b82108f04984e48b": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "e23184852e70488698cc75272c7057ae": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "ProgressStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ProgressStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "bar_color": null, - "description_width": "" - } - }, - "e6d2aa7fa6d644f39fa9eefaabbbef48": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_c6dc5ee98e1346a08067491930872eff", - "placeholder": "​", - "style": "IPY_MODEL_2a89da23f17c4b0b85ce81bcfd69cc37", - "value": "Sanity Checking DataLoader 0: 100%" - } - }, - "e8f06e2730cf4aef8427932a033252ab": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": "inline-flex", - "flex": null, - "flex_flow": "row wrap", - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": "100%" - } - }, - "ea74e30a47d043c991770a3d82aadbb5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_b3359b9ef6384c0cae5849f0b80d6cb1", - "placeholder": "​", - "style": "IPY_MODEL_169f8ac55aa14dc393b5381e56783dc5", - "value": "Validation DataLoader 0: 100%" - } - }, - "ed3ba68de443454b8be182c1901f8cfa": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "edafb607f21045d98a4b0c2059d27958": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "ee3af67a2be244988ca27a46472f18c5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_8ac7f6294ff949b1a10da96532387ebb", - "placeholder": "​", - "style": "IPY_MODEL_edafb607f21045d98a4b0c2059d27958", - "value": " 2/2 [00:01<00:00, 1.41it/s]" - } - }, - "f4b8c28792544919b47bc832cd93d4a6": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_f562f5b7289d4fcf9f310426aa620521", - "placeholder": "​", - "style": "IPY_MODEL_3b95d47d64994a9eb812488ddbac61ec", - "value": " 2/2 [00:00<00:00, 2.93it/s]" - } - }, - "f4ec778fed4749e890cdac57ef0a16f5": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_bd3cb443099643b194a13b5cd3ad037f", - "placeholder": "​", - "style": "IPY_MODEL_f7b6a5d231bc45c98c7eec9e40c5943c", - "value": "Epoch 0: 100%" - } - }, - "f562f5b7289d4fcf9f310426aa620521": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "f7b6a5d231bc45c98c7eec9e40c5943c": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "DescriptionStyleModel", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "fac4d3e8a6b64524bb0aa08036aa0588": { - "model_module": "@jupyter-widgets/controls", - "model_module_version": "1.5.0", - "model_name": "HTMLModel", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "HTMLModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "HTMLView", - "description": "", - "description_tooltip": null, - "layout": "IPY_MODEL_b662754e5b484ea58433fef79d401ce6", - "placeholder": "​", - "style": "IPY_MODEL_4977216b2e9f4e94a41520127fde4a03", - "value": "Epoch 0: 100%" - } - }, - "fbad168bdfc34eb1a439bc3334748369": { - "model_module": "@jupyter-widgets/base", - "model_module_version": "1.2.0", - "model_name": "LayoutModel", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - } - } + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: 100%|██████████| 163/163 [00:39<00:00, 4.17it/s, v_num=1, val_Total_Loss=5.420, val_Energy_MAE=1.070, val_Force_MAE=0.407, val_Stress_MAE=0.000, val_Site_Wise_MAE=0.000, val_Energy_RMSE=1.330, val_Force_RMSE=0.615, val_Stress_RMSE=0.000, val_Site_Wise_RMSE=0.000, train_Total_Loss=21.80, train_Energy_MAE=3.270, train_Force_MAE=0.572, train_Stress_MAE=0.000, train_Site_Wise_MAE=0.000, train_Energy_RMSE=3.430, train_Force_RMSE=0.870, train_Stress_RMSE=0.000, train_Site_Wise_RMSE=0.000]\n" + ] } + ], + "source": [ + "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", + "logger = CSVLogger(\"logs\", name=\"M3GNet_finetuning\")\n", + "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", + "trainer.fit(model=lit_module_finetune, train_dataloaders=train_loader, val_dataloaders=val_loader)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "252f6456-3ecf-47f0-84ca-c8e9dcc66ccc", + "metadata": { + "id": "252f6456-3ecf-47f0-84ca-c8e9dcc66ccc" + }, + "outputs": [], + "source": [ + "# save trained model\n", + "model_save_path = \"./finetuned_model/\"\n", + "model_pretrained.save(model_save_path)\n", + "# load trained model\n", + "trained_model = matgl.load_model(path = model_save_path)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd11b92f", + "metadata": { + "id": "cd11b92f" + }, + "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\")\n", + "shutil.rmtree(\"trained_model\")\n", + "shutil.rmtree(\"finetuned_model\")" + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 5 + "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.4" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/matgl/ext/ase.py b/matgl/ext/ase.py index df440ebd..f8a5c174 100644 --- a/matgl/ext/ase.py +++ b/matgl/ext/ase.py @@ -15,8 +15,6 @@ import pandas as pd import scipy.sparse as sp import torch -import matgl - from ase import Atoms, units from ase.calculators.calculator import Calculator, all_changes from ase.constraints import ExpCellFilter @@ -29,6 +27,7 @@ from pymatgen.io.ase import AseAtomsAdaptor from pymatgen.optimization.neighbors import find_points_in_spheres +import matgl from matgl.graph.converters import GraphConverter if TYPE_CHECKING: diff --git a/matgl/graph/converters.py b/matgl/graph/converters.py index 52c163e9..e9b3a0c1 100644 --- a/matgl/graph/converters.py +++ b/matgl/graph/converters.py @@ -44,6 +44,7 @@ def get_graph_from_processed_structure( element_types: Element symbols of all atoms in the structure. cart_coords: Cartisian coordinates of all atoms in the structure. is_atoms: whether the input structure object is ASE atoms object or not. + Returns: DGLGraph object, state_attr diff --git a/matgl/utils/maths.py b/matgl/utils/maths.py index bee8d79c..fe61f45f 100644 --- a/matgl/utils/maths.py +++ b/matgl/utils/maths.py @@ -9,11 +9,11 @@ import numpy as np import sympy import torch -import matgl - from scipy.optimize import brentq from scipy.special import spherical_jn +import matgl + CWD = os.path.dirname(os.path.abspath(__file__)) # Precomputed Spherical Bessel function roots in a 2D array with dimension [128, 128]. The n-th (0-based index) root of diff --git a/tests/conftest.py b/tests/conftest.py index 901e3203..db7cf242 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -59,6 +59,106 @@ def CH4(): return Molecule(["C", "H", "H", "H", "H"], coords) +@pytest.fixture(scope="session") +def AcAla3NHMe(): + coords = [ + [2.04866000, 3.03970000, -1.90538000], + [2.57508000, 1.72268000, -0.85631500], + [2.17184000, 3.30896000, -0.15238200], + [1.90655000, 2.58401000, -0.92348000], + [0.03771400, 1.25465000, -1.59488000], + [0.48396700, 2.10062000, -0.82751300], + [-0.28972800, 2.66225000, 0.13607100], + [0.16103700, 3.23064000, 0.83232600], + [-1.66536000, 2.24227000, 0.38856700], + [-1.98080000, 2.78577000, 1.28200000], + [-2.60093000, 2.60713000, -0.76094600], + [-1.65737000, 0.76935300, 0.84076700], + [-1.07671000, 0.46484900, 1.87157000], + [-3.62795000, 2.31590000, -0.52731400], + [-2.58345000, 3.68786000, -0.91203300], + [-2.28934000, 2.13627000, -1.69468000], + [-2.28796000, -0.13783200, 0.06597500], + [-2.61433000, 0.15084400, -0.84271100], + [-2.21633000, -1.56248000, 0.35525800], + [-2.49106000, -1.71026000, 1.40128000], + [-3.17539000, -2.32986000, -0.54719400], + [-0.79661200, -2.15180000, 0.24417300], + [-0.54538500, -3.20721000, 0.79546200], + [-3.09773000, -3.39555000, -0.33182000], + [-4.20586000, -2.01059000, -0.37590300], + [-2.92852000, -2.17659000, -1.60274000], + [0.08518600, -1.43854000, -0.48961600], + [-0.20393600, -0.57022000, -0.92587000], + [1.49370000, -1.76346000, -0.59747700], + [1.62352000, -2.74612000, -0.13439600], + [1.93595000, -1.80971000, -2.05523000], + [2.37375000, -0.79291000, 0.21284200], + [3.55545000, -0.63911100, -0.05660100], + [3.00626000, -2.00417000, -2.11517000], + [1.39238000, -2.59759000, -2.58040000], + [1.73079000, -0.85338400, -2.54426000], + [1.77244000, -0.14321700, 1.23186000], + [0.79538700, -0.29827700, 1.43700000], + [2.52442000, 0.70798900, 2.12658000], + [3.17617000, 0.12474300, 2.78380000], + [3.15630000, 1.39339000, 1.55717000], + [1.81944000, 1.27508000, 2.73527000], + ] + return Molecule( + [ + "H", + "H", + "H", + "C", + "O", + "C", + "N", + "H", + "C", + "H", + "C", + "C", + "O", + "H", + "H", + "H", + "N", + "H", + "C", + "H", + "C", + "C", + "O", + "H", + "H", + "H", + "N", + "H", + "C", + "H", + "C", + "C", + "O", + "H", + "H", + "H", + "N", + "H", + "C", + "H", + "H", + "H", + ], + coords, + ) + + +@pytest.fixture(scope="session") +def graph_AcAla3NHMe(AcAla3NHMe): + return get_graph(AcAla3NHMe, 5.0) + + @pytest.fixture(scope="session") def CO(): return Molecule(["C", "O"], [[0, 0, 0], [1.1, 0, 0]]) diff --git a/tests/ext/test_ase.py b/tests/ext/test_ase.py index 1200193d..da583602 100644 --- a/tests/ext/test_ase.py +++ b/tests/ext/test_ase.py @@ -25,14 +25,15 @@ def test_M3GNetCalculator(MoS): assert list(s_ase.get_stress().shape) == [6] -def test_M3GNetCalculator_mol(): - mol = molecule("CH4") - model = M3GNet(element_types=["H", "C"], is_intensive=False) - ff = Potential(model=model, calc_stresses=False) +def test_M3GNetCalculator_mol(AcAla3NHMe): + adaptor = AseAtomsAdaptor() + mol = adaptor.get_atoms(AcAla3NHMe) + ff = load_model("M3GNet-MP-2021.2.8-PES") calc = M3GNetCalculator(potential=ff) mol.set_calculator(calc) assert [mol.get_potential_energy().size] == [1] - assert list(mol.get_forces().shape) == [5, 3] + assert list(mol.get_forces().shape) == [42, 3] + np.testing.assert_allclose(mol.get_potential_energy(), -242.77213) def test_Relaxer(MoS): @@ -65,6 +66,7 @@ def test_get_graph_from_atoms(LiFePO4): # check the state features assert np.allclose(state, [0.0, 0.0]) + def test_get_graph_from_atoms_mol(): mol = molecule("CH4") a2g = Atoms2Graph(element_types=["H", "C"], cutoff=4.0) @@ -80,6 +82,7 @@ def test_get_graph_from_atoms_mol(): # check the state features assert np.allclose(state, [0.0, 0.0]) + def test_molecular_dynamics(MoS): pot = load_model("M3GNet-MP-2021.2.8-PES") for ensemble in ["nvt", "nvt_langevin", "nvt_andersen", "npt", "npt_berendsen", "npt_nose_hoover"]: diff --git a/tests/graph/test_compute.py b/tests/graph/test_compute.py index 97266dad..d8984478 100644 --- a/tests/graph/test_compute.py +++ b/tests/graph/test_compute.py @@ -149,3 +149,12 @@ def test_compute_angle(self, graph_Mo, graph_CH4): np.testing.assert_array_almost_equal( np.sort(np.array(cos_loop)), np.sort(np.array(line_graph.edata["cos_theta"])) ) + + def test_compute_three_body(self, graph_AcAla3NHMe): + mol1, g1, _ = graph_AcAla3NHMe + bv, bd = compute_pair_vector_and_distance(g1) + g1.edata["bond_vec"] = bv + g1.edata["bond_dist"] = bd + line_graph = create_line_graph(g1, 5.0) + line_graph.apply_edges(compute_theta_and_phi) + np.testing.assert_allclose(line_graph.edata["triple_bond_lengths"].detach().numpy()[0], 1.777829) From 9e1a24b8a1c0bf6f63deff37c6fd2b2bb5de5ba9 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Tue, 29 Aug 2023 01:04:14 -0700 Subject: [PATCH 03/11] improve the _three_body.py and test_M3GNetCalculator in test_ase.py --- matgl/layers/_three_body.py | 6 +++--- matgl/utils/maths.py | 10 ++++------ tests/ext/test_ase.py | 6 ++---- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/matgl/layers/_three_body.py b/matgl/layers/_three_body.py index 4f155ce4..2afec90e 100644 --- a/matgl/layers/_three_body.py +++ b/matgl/layers/_three_body.py @@ -53,11 +53,11 @@ def forward( end_atom_index = torch.gather(graph.edges()[1], 0, line_graph.edges()[1].to(torch.int64)) atoms = self.update_network_atom(node_feat) end_atom_index = torch.unsqueeze(end_atom_index, 1) - atoms = torch.squeeze(atoms[end_atom_index.long()]) + atoms = torch.squeeze(atoms[end_atom_index]) basis = three_basis * atoms three_cutoff = torch.unsqueeze(three_cutoff, dim=1) # type: ignore - weights = torch.reshape(three_cutoff[torch.stack(list(line_graph.edges()), dim=1)], (-1, 2)) # type: ignore - weights = torch.prod(weights, axis=-1) # type: ignore + weights = three_cutoff[torch.stack(list(line_graph.edges()), dim=1)].view(-1, 2) # type: ignore + weights = torch.prod(weights, dim=-1) # type: ignore basis = basis * weights[:, None] new_bonds = scatter_sum( basis.to(matgl.float_th), diff --git a/matgl/utils/maths.py b/matgl/utils/maths.py index fe61f45f..71991d2f 100644 --- a/matgl/utils/maths.py +++ b/matgl/utils/maths.py @@ -101,13 +101,11 @@ def get_segment_indices_from_n(ns): ns: torch.Tensor, the number of atoms/bonds array Returns: - object: - - Returns: segment indices tensor + torch.Tensor: segment indices tensor """ - B = ns - A = torch.arange(B.size(dim=0)) - return A.repeat_interleave(B, dim=0) + segments = torch.zeros(ns.sum(), dtype=matgl.int_th) + segments[ns.cumsum(0)[:-1]] = 1 + return segments.cumsum(0) def get_range_indices_from_n(ns): diff --git a/tests/ext/test_ase.py b/tests/ext/test_ase.py index da583602..b07e00a0 100644 --- a/tests/ext/test_ase.py +++ b/tests/ext/test_ase.py @@ -8,21 +8,19 @@ from pymatgen.io.ase import AseAtomsAdaptor from matgl import load_model -from matgl.apps.pes import Potential from matgl.ext.ase import Atoms2Graph, M3GNetCalculator, MolecularDynamics, Relaxer -from matgl.models import M3GNet def test_M3GNetCalculator(MoS): adaptor = AseAtomsAdaptor() s_ase = adaptor.get_atoms(MoS) # type: ignore - model = M3GNet(element_types=["Mo", "S"], is_intensive=False) - ff = Potential(model=model) + ff = load_model("M3GNet-MP-2021.2.8-PES") calc = M3GNetCalculator(potential=ff) s_ase.set_calculator(calc) assert [s_ase.get_potential_energy().size] == [1] assert list(s_ase.get_forces().shape) == [2, 3] assert list(s_ase.get_stress().shape) == [6] + np.testing.assert_allclose(s_ase.get_potential_energy(), -10.312888) def test_M3GNetCalculator_mol(AcAla3NHMe): From 83b8eb8c844ad082f0bb6fad7b374631f7f98765 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Thu, 31 Aug 2023 15:17:27 -0700 Subject: [PATCH 04/11] add cpu() in ase.py and compute.py to enable the GPU usage for MatGL-LAMMPS interface --- matgl/ext/ase.py | 10 +++++----- matgl/graph/compute.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/matgl/ext/ase.py b/matgl/ext/ase.py index f8a5c174..0437298e 100644 --- a/matgl/ext/ase.py +++ b/matgl/ext/ase.py @@ -177,14 +177,14 @@ def calculate( else: energies, forces, stresses, hessians = self.potential(graph, state_attr_default) self.results.update( - energy=energies.detach().numpy(), - free_energy=energies.detach().numpy(), - forces=forces.detach().numpy(), + energy=energies.detach().cpu().numpy(), + free_energy=energies.detach().cpu().numpy(), + forces=forces.detach().cpu().numpy(), ) if self.compute_stress: - self.results.update(stress=stresses.detach().numpy() * self.stress_weight) + self.results.update(stress=stresses.detach().cpu().numpy() * self.stress_weight) if self.compute_hessian: - self.results.update(hessian=hessians.detach().numpy()) + self.results.update(hessian=hessians.detach().cpu().numpy()) class Relaxer: diff --git a/matgl/graph/compute.py b/matgl/graph/compute.py index b878ad51..a8f08d89 100644 --- a/matgl/graph/compute.py +++ b/matgl/graph/compute.py @@ -22,7 +22,7 @@ def compute_3body(g: dgl.DGLGraph): n_triple_s (np.ndarray): number of three-body angles for each structure """ n_atoms = g.num_nodes() - first_col = g.edges()[0].numpy().reshape(-1, 1) + first_col = g.edges()[0].cpu().numpy().reshape(-1, 1) all_indices = np.arange(n_atoms).reshape(1, -1) n_bond_per_atom = np.count_nonzero(first_col == all_indices, axis=0) n_triple_i = n_bond_per_atom * (n_bond_per_atom - 1) From 7db50e76017013be8c36d9c3f84d688ad7c8befc Mon Sep 17 00:00:00 2001 From: kenko911 Date: Thu, 31 Aug 2023 17:37:18 -0700 Subject: [PATCH 05/11] included the unit-test for hessian test_ase.py to improve the coverage score --- tests/ext/test_ase.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/ext/test_ase.py b/tests/ext/test_ase.py index b07e00a0..32069f5d 100644 --- a/tests/ext/test_ase.py +++ b/tests/ext/test_ase.py @@ -15,11 +15,13 @@ def test_M3GNetCalculator(MoS): adaptor = AseAtomsAdaptor() s_ase = adaptor.get_atoms(MoS) # type: ignore ff = load_model("M3GNet-MP-2021.2.8-PES") + ff.calc_hessian = True calc = M3GNetCalculator(potential=ff) s_ase.set_calculator(calc) assert [s_ase.get_potential_energy().size] == [1] assert list(s_ase.get_forces().shape) == [2, 3] assert list(s_ase.get_stress().shape) == [6] + assert list(calc.results["hessian"].shape) == [6, 6] np.testing.assert_allclose(s_ase.get_potential_energy(), -10.312888) From 1253ba5403d74806666ba5d1f308852f091bad6c Mon Sep 17 00:00:00 2001 From: kenko911 Date: Tue, 5 Sep 2023 10:17:14 -0700 Subject: [PATCH 06/11] remove reducdant torch.unique for finding the maximum three_body index and little cleanup in united tests --- matgl/graph/compute.py | 2 +- matgl/models/_m3gnet.py | 2 +- tests/layers/test_graph_conv.py | 14 +------------- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/matgl/graph/compute.py b/matgl/graph/compute.py index a8f08d89..2f848639 100644 --- a/matgl/graph/compute.py +++ b/matgl/graph/compute.py @@ -56,7 +56,7 @@ def compute_3body(g: dgl.DGLGraph): src_id = torch.tensor(triple_bond_indices[:, 0], dtype=matgl.int_th) dst_id = torch.tensor(triple_bond_indices[:, 1], dtype=matgl.int_th) l_g = dgl.graph((src_id, dst_id)) - three_body_id = torch.unique(torch.concatenate(l_g.edges())) + three_body_id = torch.concatenate(l_g.edges()) n_triple_ij = torch.tensor(n_triple_ij, dtype=matgl.int_th) max_three_body_id = torch.max(three_body_id) + 1 if three_body_id.numel() > 0 else 0 l_g.ndata["bond_dist"] = g.edata["bond_dist"][:max_three_body_id] diff --git a/matgl/models/_m3gnet.py b/matgl/models/_m3gnet.py index e190cb2e..65e392a5 100644 --- a/matgl/models/_m3gnet.py +++ b/matgl/models/_m3gnet.py @@ -238,7 +238,7 @@ def forward( l_g.ndata["bond_dist"] = g.edata["bond_dist"][valid_three_body] l_g.ndata["pbc_offset"] = g.edata["pbc_offset"][valid_three_body] else: - three_body_id = torch.unique(torch.concatenate(l_g.edges())) + three_body_id = torch.concatenate(l_g.edges()) max_three_body_id = torch.max(three_body_id) + 1 if three_body_id.numel() > 0 else 0 l_g.ndata["bond_vec"] = g.edata["bond_vec"][:max_three_body_id] l_g.ndata["bond_dist"] = g.edata["bond_dist"][:max_three_body_id] diff --git a/tests/layers/test_graph_conv.py b/tests/layers/test_graph_conv.py index 4b59db87..ad3c48df 100644 --- a/tests/layers/test_graph_conv.py +++ b/tests/layers/test_graph_conv.py @@ -6,11 +6,7 @@ import torch from torch import nn -from matgl.graph.compute import ( - compute_theta_and_phi, - create_line_graph, -) -from matgl.layers import BondExpansion, EmbeddingBlock, SphericalBesselWithHarmonics +from matgl.layers import BondExpansion, EmbeddingBlock from matgl.layers._graph_convolution import ( MLP, M3GNetBlock, @@ -88,10 +84,6 @@ def test_m3gnet_graph_conv(self, graph_MoS): bond_expansion = BondExpansion(max_l=3, max_n=3, cutoff=5.0, rbf_type="SphericalBessel", smooth=False) bond_basis = bond_expansion(bond_dist) g1.edata["rbf"] = bond_basis - sb_and_sh = SphericalBesselWithHarmonics(max_n=3, max_l=3, cutoff=5.0, use_smooth=False, use_phi=False) - l_g1 = create_line_graph(g1, threebody_cutoff=4.0) - l_g1.apply_edges(compute_theta_and_phi) - sb_and_sh(l_g1) max_n = 3 max_l = 3 num_node_feats = 16 @@ -137,10 +129,6 @@ def test_m3gnet_block(self, graph_MoS): bond_expansion = BondExpansion(max_l=3, max_n=3, cutoff=5.0, rbf_type="SphericalBessel", smooth=False) bond_basis = bond_expansion(g1.edata["bond_dist"]) g1.edata["rbf"] = bond_basis - sb_and_sh = SphericalBesselWithHarmonics(max_n=3, max_l=3, cutoff=5.0, use_smooth=False, use_phi=False) - l_g1 = create_line_graph(g1, threebody_cutoff=4.0) - l_g1.apply_edges(compute_theta_and_phi) - sb_and_sh(l_g1) num_node_feats = 16 num_edge_feats = 32 num_state_feats = 64 From ca79fab8ccb444bf62685ff2346af4dc1c173517 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Wed, 13 Sep 2023 14:19:03 -0700 Subject: [PATCH 07/11] add united test for trainer.test and description in the example --- ...raining a M3GNet Potential with PyTorch Lightning.ipynb | 7 ++++--- tests/utils/test_training.py | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb index 1f899118..b1e6175c 100644 --- a/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb +++ b/examples/Training a M3GNet Potential with PyTorch Lightning.ipynb @@ -268,7 +268,8 @@ "source": [ "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", "logger = CSVLogger(\"logs\", name=\"M3GNet_training\")\n", - "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", + "# Inference mode = False is required for calculating forces, stress in test mode and prediction mode\n", + "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger, inference_mode=False)\n", "trainer.fit(model=lit_module, train_dataloaders=train_loader, val_dataloaders=val_loader)" ] }, @@ -405,7 +406,7 @@ "source": [ "# If you wish to disable GPU or MPS (M1 mac) training, use the accelerator=\"cpu\" kwarg.\n", "logger = CSVLogger(\"logs\", name=\"M3GNet_finetuning\")\n", - "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger)\n", + "trainer = pl.Trainer(max_epochs=1, accelerator=\"cpu\", logger=logger, inference_mode=False)\n", "trainer.fit(model=lit_module_finetune, train_dataloaders=train_loader, val_dataloaders=val_loader)" ] }, @@ -467,7 +468,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.4" + "version": "3.10.9" } }, "nbformat": 4, diff --git a/tests/utils/test_training.py b/tests/utils/test_training.py index 4e9c2691..5b923469 100644 --- a/tests/utils/test_training.py +++ b/tests/utils/test_training.py @@ -113,9 +113,10 @@ def test_m3gnet_training(self, LiFePO4, BaNiO3): model = M3GNet(element_types=element_types, is_intensive=False) lit_model = PotentialLightningModule(model=model, stress_weight=0.0001) # We will use CPU if MPS is available since there is a serious bug. - trainer = pl.Trainer(max_epochs=5, accelerator=device) + trainer = pl.Trainer(max_epochs=5, accelerator=device, inference_mode=False) trainer.fit(model=lit_model, train_dataloaders=train_loader, val_dataloaders=val_loader) + trainer.test(lit_model, dataloaders=test_loader) pred_LFP_energy = model.predict_structure(LiFePO4) pred_BNO_energy = model.predict_structure(BaNiO3) From e4171d6743df123c7e1116cbb16985a13b05da86 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Mon, 18 Sep 2023 20:26:16 -0700 Subject: [PATCH 08/11] add option for PES training without stresses --- matgl/apps/pes.py | 9 ++-- matgl/graph/data.py | 12 +++-- matgl/layers/_basis.py | 9 ++-- .../M3GNet-MP-2021.2.8-PES/model.json | 2 +- .../M3GNet-MP-2021.2.8-PES/model.pt | Bin 3743 -> 3759 bytes tests/graph/test_data.py | 44 +++++++++++++--- tests/utils/test_training.py | 48 ++++++++++++++++++ 7 files changed, 104 insertions(+), 20 deletions(-) diff --git a/matgl/apps/pes.py b/matgl/apps/pes.py index 5a9d3343..38932b1a 100644 --- a/matgl/apps/pes.py +++ b/matgl/apps/pes.py @@ -7,6 +7,7 @@ from torch import nn from torch.autograd import grad +import matgl from matgl.layers import AtomRef from matgl.utils.io import IOMixIn @@ -52,14 +53,12 @@ def __init__( self.calc_site_wise = calc_site_wise self.element_refs: AtomRef | None if element_refs is not None: - self.element_refs = AtomRef(property_offset=element_refs) + self.element_refs = AtomRef(property_offset=torch.tensor(element_refs, dtype=matgl.float_th)) else: self.element_refs = None - data_mean = data_mean or 0 - data_std = data_std or 1 - self.data_mean = data_mean.clone().detach() if isinstance(data_mean, torch.Tensor) else torch.tensor(data_mean) - self.data_std = data_std.clone().detach() if isinstance(data_std, torch.Tensor) else torch.tensor(data_std) + self.register_buffer("data_mean", torch.tensor(data_mean, dtype=matgl.float_th)) + self.register_buffer("data_std", torch.tensor(data_std, dtype=matgl.float_th)) def forward( self, g: dgl.DGLGraph, state_attr: torch.Tensor | None = None, l_g: dgl.DGLGraph | None = None diff --git a/matgl/graph/data.py b/matgl/graph/data.py index 1f4852ac..1986d265 100644 --- a/matgl/graph/data.py +++ b/matgl/graph/data.py @@ -36,14 +36,18 @@ def collate_fn(batch, include_line_graph: bool = False): return g, labels, state_attr -def collate_fn_efs(batch): +def collate_fn_efs(batch, include_stress: bool = True): """Merge a list of dgl graphs to form a batch.""" graphs, line_graphs, state_attr, labels = map(list, zip(*batch)) g = dgl.batch(graphs) l_g = dgl.batch(line_graphs) - e = torch.tensor([d["energies"] for d in labels]) - f = torch.vstack([d["forces"] for d in labels]) - s = torch.vstack([d["stresses"] for d in labels]) + e = torch.tensor([d["energies"] for d in labels]) # type: ignore + f = torch.vstack([d["forces"] for d in labels]) # type: ignore + s = ( + torch.vstack([d["stresses"] for d in labels]) # type: ignore + if include_stress is True + else torch.tensor(np.zeros(e.size(dim=0)), dtype=matgl.float_th) + ) state_attr = torch.stack(state_attr) return g, l_g, state_attr, e, f, s diff --git a/matgl/layers/_basis.py b/matgl/layers/_basis.py index 3a902fe0..598b600e 100644 --- a/matgl/layers/_basis.py +++ b/matgl/layers/_basis.py @@ -70,7 +70,7 @@ def __init__(self, max_l: int, max_n: int = 5, cutoff: float = 5.0, smooth: bool super().__init__() self.max_l = max_l self.max_n = max_n - self.cutoff = torch.tensor(cutoff) + self.register_buffer("cutoff", torch.tensor(cutoff)) self.smooth = smooth if smooth: self.funcs = self._calculate_smooth_symbolic_funcs() @@ -116,7 +116,7 @@ def _call_sbf(self, r): results = [] factor = torch.tensor(sqrt(2.0 / self.cutoff**3)) for i in range(self.max_l): - root = roots[i] + root = torch.tensor(roots[i]) func = self.funcs[i] func_add1 = self.funcs[i + 1] results.append( @@ -218,7 +218,7 @@ def forward(self, x: torch.Tensor) -> torch.Tensor: return result / self.interval * self.scale_factor -class SphericalHarmonicsFunction: +class SphericalHarmonicsFunction(nn.Module): """Spherical Harmonics function.""" def __init__(self, max_l: int, use_phi: bool = True): @@ -228,6 +228,7 @@ def __init__(self, max_l: int, use_phi: bool = True): use_phi: bool, whether to use the polar angle. If not, the function will compute `Y_l^0`. """ + super().__init__() self.max_l = max_l self.use_phi = use_phi funcs = [] @@ -244,7 +245,7 @@ def __init__(self, max_l: int, use_phi: bool = True): self.funcs = [sympy.lambdify([costheta, phi], i, [{"conjugate": _conjugate}, torch]) for i in self.orig_funcs] self.funcs[0] = _y00 - def __call__(self, costheta, phi=None): + def forward(self, costheta, phi=None): """Args: costheta: Cosine of the azimuthal angle phi: torch.Tensor, the polar angle. diff --git a/pretrained_models/M3GNet-MP-2021.2.8-PES/model.json b/pretrained_models/M3GNet-MP-2021.2.8-PES/model.json index 4adf89ff..d1196e05 100644 --- a/pretrained_models/M3GNet-MP-2021.2.8-PES/model.json +++ b/pretrained_models/M3GNet-MP-2021.2.8-PES/model.json @@ -127,7 +127,7 @@ "data_std": "tensor(0.3896)" } }, - "data_mean": null, + "data_mean": 0.0, "data_std": 0.389599794401098, "element_refs": [ -3.47784146, diff --git a/pretrained_models/M3GNet-MP-2021.2.8-PES/model.pt b/pretrained_models/M3GNet-MP-2021.2.8-PES/model.pt index 90396d2652b790089e67b3cf518cf27f0044eb47..0f4de6657bc10be5acbd584c2b0c4110a2456710 100644 GIT binary patch delta 313 zcmbO)yIyvJl#~#I07GtmN@`AgUTV31N@7W(UO{$_n-dSiMw9bwobC)zu$hH@6*JGq zxk=lKxEL5fc!HFK0ET9L1CZ9uU$|y5iVHBvp&6}j=;kCfc_EMV2t#guN@|XNN@7W(UO{$_o09-T6cB7QInT!Ex0#216*DJCTXbs{ z7Xw4q Date: Tue, 19 Sep 2023 15:52:44 -0700 Subject: [PATCH 09/11] merged the changes and fix errors --- tests/ext/test_ase.py | 8 ++++---- tests/utils/test_io.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ext/test_ase.py b/tests/ext/test_ase.py index 32069f5d..63b2efba 100644 --- a/tests/ext/test_ase.py +++ b/tests/ext/test_ase.py @@ -14,7 +14,7 @@ def test_M3GNetCalculator(MoS): adaptor = AseAtomsAdaptor() s_ase = adaptor.get_atoms(MoS) # type: ignore - ff = load_model("M3GNet-MP-2021.2.8-PES") + ff = load_model("pretrained_models/M3GNet-MP-2021.2.8-PES/") ff.calc_hessian = True calc = M3GNetCalculator(potential=ff) s_ase.set_calculator(calc) @@ -28,7 +28,7 @@ def test_M3GNetCalculator(MoS): def test_M3GNetCalculator_mol(AcAla3NHMe): adaptor = AseAtomsAdaptor() mol = adaptor.get_atoms(AcAla3NHMe) - ff = load_model("M3GNet-MP-2021.2.8-PES") + ff = load_model("pretrained_models/M3GNet-MP-2021.2.8-PES/") calc = M3GNetCalculator(potential=ff) mol.set_calculator(calc) assert [mol.get_potential_energy().size] == [1] @@ -37,7 +37,7 @@ def test_M3GNetCalculator_mol(AcAla3NHMe): def test_Relaxer(MoS): - pot = load_model("M3GNet-MP-2021.2.8-PES") + pot = load_model("pretrained_models/M3GNet-MP-2021.2.8-PES/") r = Relaxer(pot) results = r.relax(MoS, traj_file="MoS_relax.traj") s = results["final_structure"] @@ -84,7 +84,7 @@ def test_get_graph_from_atoms_mol(): def test_molecular_dynamics(MoS): - pot = load_model("M3GNet-MP-2021.2.8-PES") + pot = load_model("pretrained_models/M3GNet-MP-2021.2.8-PES/") for ensemble in ["nvt", "nvt_langevin", "nvt_andersen", "npt", "npt_berendsen", "npt_nose_hoover"]: md = MolecularDynamics(MoS, potential=pot, ensemble=ensemble, taut=0.1, taup=0.1, compressibility_au=10) md.run(10) diff --git a/tests/utils/test_io.py b/tests/utils/test_io.py index b057a24e..71b5cef9 100644 --- a/tests/utils/test_io.py +++ b/tests/utils/test_io.py @@ -71,7 +71,7 @@ def test_get_available_pretrained_models(): def test_load_model(): # Load model from name. - model = load_model("M3GNet-MP-2021.2.8-PES") + model = load_model("M3GNet-MP-2021.2.8-DIRECT-PES") assert issubclass(model.__class__, torch.nn.Module) # Load model from a full path. From 15427dc7b04e2e23668ccfd67db35c2112cf4d7f Mon Sep 17 00:00:00 2001 From: kenko911 Date: Wed, 20 Sep 2023 09:58:21 -0700 Subject: [PATCH 10/11] add backward compatibility for data_mean in pes.py --- matgl/apps/pes.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/matgl/apps/pes.py b/matgl/apps/pes.py index 38932b1a..1b98e0da 100644 --- a/matgl/apps/pes.py +++ b/matgl/apps/pes.py @@ -56,7 +56,9 @@ def __init__( self.element_refs = AtomRef(property_offset=torch.tensor(element_refs, dtype=matgl.float_th)) else: self.element_refs = None - + # for backward compatibility + if data_mean is None: + data_mean = 0.0 self.register_buffer("data_mean", torch.tensor(data_mean, dtype=matgl.float_th)) self.register_buffer("data_std", torch.tensor(data_std, dtype=matgl.float_th)) From 07e5b04bbf2b422398249a7b3327d05bd696d374 Mon Sep 17 00:00:00 2001 From: kenko911 Date: Thu, 28 Sep 2023 13:09:18 -0700 Subject: [PATCH 11/11] An Example for the simple training of M3GNet formation energy model is added --- ... Energy Model with PyTorch Lightning.ipynb | 642 ++++++++++++++++++ ...Net Potential with PyTorch Lightning.ipynb | 2 +- 2 files changed, 643 insertions(+), 1 deletion(-) create mode 100644 examples/Training a M3GNet Formation Energy Model with PyTorch Lightning.ipynb 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)" ] }, {