Note
Go to the end to download the full example code.
Fundamentals of TorchANI#
The TorchANI library provides a set of pre-trained models that can be used directly. All
provided models are subclasses of class torchani.arch.ANI.
It also contains classes such as torchani.aev.AEVComputer, torchani.nn.ANINetworks,
and torchani.sae.SelfEnergy that can be combined to compute molecular energies
from the cartesian coordinates of molecules, and it includes tools to deal with ANI
datasets in the submodule torchani.datasets.
Here introduce the basics of the library, and we show how to use the built-in models to predict useful quantities (such as energies, forces, and ensemble statistics) of single molecules and batches.
# To begin with, let's first import the modules we will use:
import torch
import torchani
from torchani import single_point
torchani dependens on the torch library. Some familiarity with it is helpful,
but you don’t need to be an expert with torch in order to use torchani. The
main object in torch is a Tensor, which is very similar to a numpy
multi-dimensional array. Its three most important properties are data type
(dtype), device, and shape. Each time you create one, you can pass arguments
to specify these. Lets create a couple as an example
device = "cpu"
# The ``dtype`` of this tensor is ``torch.int64``, and its shape is (1, 5)
atomic_nums = torch.tensor([[6, 1, 1, 1, 1]], device=device)
# The ``dtype`` of this one is ``torch.float32``, its shape is (1, 5, 3)
coords = torch.tensor(
[
[
[0.03192167, 0.00638559, 0.01301679],
[-0.83140486, 0.39370209, -0.26395324],
[-0.66518241, -0.84461308, 0.20759389],
[0.45554739, 0.54289633, 0.81170881],
[0.66091919, -0.16799635, -0.91037834],
]
],
device=device,
)
These tensors represent the coordinates (in angstrom) and atomic_nums of a methane
molecule. We put the tensors in "cpu", but you can use device="cuda" if you
have a CUDA capable GPU. Tensors of coordinates in torchani have shape
(molecules, atoms, 3) and dtype torch.float32|64, tensors of atomic numbers
have shape (molecules, atoms), and dtype torch.long.
torchani provides a set of pre-trained models, which are predictors that calculate
properties of molecular systems. The built-in models can be used directly ANI.
Lets load the ANI-2x model, which is an ‘ensemble’ of 8 sub-models trained with different initial seeds, and to different sections of the “ANI-2x dataset”. Using an ensemble is recommended, since althought its a bit more costly than using a single model, its significantly more accurate.
As you can see, similarly to tensors, torchani models also have a device and a
dtype, which are the device and dtype their internal parameters. If your inputs
are in CPU, then the model should be in CPU, and similarly for CUDA GPUs. By
default all models have dtype=torch.float32.
Now let’s perform a single point calculation to compute energy and force:
And print to see the result:
Energy (Hartree): -40.45979309082031
Force (Hartree / Å):
tensor([[[ 0.048, -0.130, -0.055],
[-0.135, 0.158, -0.078],
[ 0.080, -0.039, 0.039],
[ 0.025, 0.008, 0.043],
[-0.018, 0.004, 0.051]]])
you can get the atomic energies (WARNING: these have no physical meaning) by calling:
result = single_point(model, atomic_nums, coords, atomic_energies=True)
energy = result["energies"]
atomic_energies = result["atomic_energies"]
this gives you the average (shifted) energies over all models of the ensemble by default, with the same shape as the coordinates. (Dummy atoms, if present, will have an atomic energy of zero.)
print("Atomic energies: \n", atomic_energies)
Atomic energies:
tensor([[-38.080, -0.581, -0.591, -0.605, -0.604]])
Ensemble statistics are also easily obtained with this function, by passing ensemble_values
result = single_point(model, atomic_nums, coords, ensemble_values=True)
ensemble_std = result["ensemble_std"] # standard deviation of the energy
qbcs = result["qbcs"] # QBC (Query-By-Committee) scores
print("Ensemble energy Std: \n", ensemble_std)
print("Ensemble QBC: \n", qbcs)
Ensemble energy Std:
tensor([0.000])
Ensemble QBC:
tensor([0.000])
Some models (such as torchani.models.ANImbis) can also predict atomic charges
charge_model = torchani.models.ANImbis(device=device)
result = single_point(
charge_model, atomic_nums, coords, atomic_energies=True, atomic_charges=True
)
energy = result["energies"]
atomic_charges = result["atomic_charges"]
print("Atomic charges: \n", atomic_charges)
Atomic charges:
tensor([[-0.710, 0.168, 0.159, 0.207, 0.176]])