Molecule MolGraph featurizers#
[1]:
from chemprop.featurizers.molgraph.molecule import SimpleMoleculeMolGraphFeaturizer
This is an example molecule to featurize.
[2]:
from rdkit import Chem
mol_to_featurize = Chem.MolFromSmiles("CC")
Simple molgraph featurizer#
A MolGraph represents the graph featurization of a molecule. It is made of atom features (V), bond features (E), and a mapping between atoms and bonds (edge_index and rev_edge_index). It is created by SimpleMoleculeMolGraphFeaturizer.
[3]:
featurizer = SimpleMoleculeMolGraphFeaturizer()
featurizer(mol_to_featurize)
[3]:
MolGraph(V=array([[0. , 0. , 0. , 0. , 0. , 1. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
1. , 0. , 0. , 0. , 0. , 0. , 0. ,
1. , 0. , 1. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0.12011],
[0. , 0. , 0. , 0. , 0. , 1. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
1. , 0. , 0. , 0. , 0. , 0. , 0. ,
1. , 0. , 1. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0.12011]], dtype=float32), E=array([[0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.]]), edge_index=array([[0, 1],
[1, 0]]), rev_edge_index=array([1, 0]))
CuikmolmakerMolGraphFeaturizer#
Unlike SimpleMoleculeMolGraphFeaturizer, which featurizes a single molecule at a time and returns one MolGraph, CuikmolmakerMolGraphFeaturizer featurizes an entire batch of SMILES strings in a single call and returns one batched graph (BatchCuikMolGraph). It relies on the cuik-molmaker package to (1) convert the SMILES strings into Chem.Mol objects, (2) calculate the atom and bond features for every molecule, and (3) batch all the individual graphs together — all in the
C++ layer.
Because the atoms and bonds of the whole batch are featurized together in C++ rather than one molecule at a time in Python, this provides significant acceleration and memory savings: there is no need to build, cache, or collate a separate MolGraph for each molecule. This makes it especially useful for large datasets where pre-computing and caching the featurized graphs is not feasible.
When creating the featurizer, you can give it options to control step 1 (currently only add_h). For step 2, the featurizer takes a single atom_featurizer_mode (V1, V2, ORGANIC, or RIGR) that determines which atom and bond features to calculate, instead of taking separate atom and bond featurizers.
[4]:
from chemprop.featurizers.molgraph.molecule import CuikmolmakerMolGraphFeaturizer
featurizer = CuikmolmakerMolGraphFeaturizer(atom_featurizer_mode="organic", add_h=True)
smi_list = ["C" * i for i in range(1, 20)]
bmg = featurizer(smi_list)
print(bmg)
<chemprop.featurizers.molgraph.molecule.BatchCuikMolGraph object at 0x7b1c977ed0d0>
One difference between SimpleMolGraphFeaturizer and CuikmolmakerMolGraphFeaturizer is its treatment of empty SMILES string. SimpleMolGraphFeaturizer returns a feature tensor with one atom for the empty SMILES string while CuikmolmakerMolGraphFeaturizer skips the SMILES string entirely.
[5]:
# Illustration of difference between SimpleMolGraphFeaturizer and CuikmolmakerMolGraphFeaturizer
smi_list = ["C"] * 8
smi_list_1empty = smi_list.copy()
smi_list_1empty[0] = ""
cuik_featurizer = CuikmolmakerMolGraphFeaturizer(atom_featurizer_mode="organic")
bmg = cuik_featurizer(smi_list_1empty)
bmg.V.shape # Shape of atom features from CuikmolmakerMolGraphFeaturizer
[5]:
torch.Size([7, 44])
[6]:
from chemprop.data.collate import BatchMolGraph
from chemprop.featurizers import MultiHotAtomFeaturizer
# Form MolGraphs for all molecules in smi_list_invalid using SimpleMoleculeMolGraphFeaturizer
simple_featurizer = SimpleMoleculeMolGraphFeaturizer(atom_featurizer=MultiHotAtomFeaturizer.organic())
molgraphs = [simple_featurizer(Chem.MolFromSmiles(smi)) for smi in smi_list_1empty]
# Form a BatchMolGraph from the list of MolGraphs
simple_bmg = BatchMolGraph(molgraphs)
simple_bmg.V.shape # Shape of atom features from SimpleMolGraphFeaturizer
[6]:
torch.Size([8, 44])
Custom#
The atom and bond featurizers used by the molgraph featurizer are customizable.
[7]:
from chemprop.featurizers import MultiHotAtomFeaturizer, MultiHotBondFeaturizer
atom_featurizer = MultiHotAtomFeaturizer.organic()
bond_featurizer = MultiHotBondFeaturizer(stereos=[0, 1, 2, 3, 4])
featurizer = SimpleMoleculeMolGraphFeaturizer(
atom_featurizer=atom_featurizer, bond_featurizer=bond_featurizer
)
featurizer(mol_to_featurize)
[7]:
MolGraph(V=array([[0. , 0. , 1. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 1. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. , 0. , 1. , 0. ,
0. , 0.12011],
[0. , 0. , 1. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 0. , 0. ,
0. , 0. , 0. , 1. , 0. , 1. , 0. ,
0. , 0. , 0. , 0. , 0. , 0. , 1. ,
0. , 0. , 0. , 0. , 0. , 1. , 0. ,
0. , 0.12011]], dtype=float32), E=array([[0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]]), edge_index=array([[0, 1],
[1, 0]]), rev_edge_index=array([1, 0]))
Extra atom and bond features#
If your datapoints have extra atom or bond features, the molgraph featurizer needs to know the length of the extra features when it is created so that the empty Chem.Mol (Chem.MolFromSmiles("")) is featurized correctly and so that the bond feature array is the correct shape.
[8]:
n_extra_atom_features = 3
n_extra_bond_features = 4
featurizer = SimpleMoleculeMolGraphFeaturizer(
extra_atom_fdim=n_extra_atom_features, extra_bond_fdim=n_extra_bond_features
)
The dataset is given this custom featurizer and automatically handles the featurization including passing extra atom and bond features for each datapoint.