DeepChem — A framework for using ML and DL for Life Science and Chemoinformatics | by Aditya Bhattacharya | Towards Data Science

Application of Machine Learning and Deep Learning for Drug Discovery, Genomics, Microsocopy and Quantum Chemistry can create radical impact and holds the potential to significantly accelerate the process of medical research and vaccine development, which is a necessity for any pandemic like Covid19.
Before we even begin, this article is a very high level one and specifically targeted for Data Scientists and ML Researchers interested in Drug Discovery, especially during the time of an existing pandemic like Covid19. If you are some one with a strong background in Bio-informatics or Chem-informatics and wants to venture into the world of data science for these use-cases, please reach out to me through any of the options mentioned here, and we can discuss few interesting opportunities for the greater good of mankind.
DeepChem, an open source framework, which internally uses TensorFlow, that has been specifically designed to simplify the creation of deep learning models for various life science applications.
In this tutorial, we will see how to setup DeepChem and we will see how to use DeepChem for :
1. training a model that can predict toxicity of molecules
2. training a model to predict solubility of molecules
3. using SMART strings to query molecular structures.
Although, in multiple sources, I have seen users have expressed their concern in setting up DeepChem in Windows, Linux and Mac environments, but I found it quite easy to do that using pip installer.
The DeepChem development team, is very active and they do provide daily builds, so I would like everyone to take a look at their pypi page: https://pypi.org/project/deepchem/#history and install a suitable version in case if the latest version has any issue. A simple pip install deepchem would install the very latest version.
Next, along with DeepChem, you would require TensorFlow to be installed. I had installed the latest version of TensorFlow using pip install tensorflow and RDkit which is an open source Cheminformatics software package. For RDkit and for installing in Windows, I did not find any reliable pip installer, so that installed it from https://anaconda.org/rdkit/rdkit using the conda installer : conda install -c rdkit rdkit
Once these three modules are installed, we are ready to start with our experiments.
Molecular toxicity can be defined as sum of adverse effects exhibited by a substance on any organism. Computational methods can actually determine the toxicity of a given compound using chemical and strcutral properties of the molecule and molecular featurization using molecular descriptors (Dong et al., 2015) and fingerprints (Xue and Bajorath, 2000), can effectively extract the chemical and structural information inherent in any given molecule for prediction-based approaches.
For predicting toxicity, we will use the Tox21 toxicity dataset from MoleculeNet and we will use DeepChem to load the required dataset.
import numpy as npimport deepchem as dctox21_tasks, tox21_datasets, transformers = dc.molnet.load_tox21()
After this we will see all the toxicity classes, just be printing tox21_tasks
['NR-AR', 'NR-AR-LBD', 'NR-AhR', 'NR-Aromatase', 'NR-ER', 'NR-ER-LBD', 'NR-PPAR-gamma', 'SR-ARE', 'SR-ATAD5', 'SR-HSE', 'SR-MMP', 'SR-p53']
We can divide the entire dataset into training, testing and validation dataset by:
train_dataset, valid_dataset, test_dataset = tox21_datasets
If we check the distribution of the dataset, we will see that the dataset is not balanced, so we would need to balance the dataset as typically we are trying to solve a MultiClass Classification problem. And so if the dataset is not balanced, the majority class will add bias to the classifier, which will skew the results. So, the transformer object used by default is a balancing transformer.
print(transformers)[<deepchem.trans.transformers.BalancingTransformer at 0x26b5642dc88>]
now, for the training part :
model = dc.models.MultitaskClassifier(n_tasks=12, n_features=1024, layer_sizes=[1000])model.fit(train_dataset, nb_epoch=10)metric = dc.metrics.Metric(dc.metrics.roc_auc_score, np.mean)train_scores = model.evaluate(train_dataset, [metric], transformers)test_scores = model.evaluate(test_dataset, [metric], transformers)
Now, DeepChem’s submodule contains a variety of dc.models different life science–specific models.
And finally we see, that the final AUC-ROC scores are:
{'training mean-roc_auc_score': 0.9556297601807405}{'testing mean-roc_auc_score': 0.7802496964641786}
This shows us that there is some over-fitting in the model as the test dataset metric scores are much less as compared to the train-set. But, nevertheless, now we do have a model that can predict toxicity from molecules!
Solubility is a measure, which shows how easily a molecule can dissolve in water. For any drug discovery, it is very important to check the solubility of the compound as the drug should dissolve into the patient’s bloodstream to have the required therapeutic effect. Usually, medicinal chemists spend a lot of time in modifying molecules to increase this property of solubility. In this section we will use DeepChem to predict solubility of molecules.
We will be using the delaney dataset from MoleculeNet, which is also available in DeepChem, for predicting molecular solubility.
# load the featurized data tasks, datasets, transformers = dc.molnet.load_delaney(featurizer='GraphConv')# Split into traintest-validation datasettrain_dataset, valid_dataset, test_dataset = datasets# Fit the modelmodel = dc.models.GraphConvModel(n_tasks=1, mode='regression', dropout=0.2)model.fit(train_dataset, nb_epoch=100)# Use r2 score as model evaluation metricmetric = dc.metrics.Metric(dc.metrics.pearson_r2_score)print(model.evaluate(train_dataset, [metric], transformers))print(model.evaluate(test_dataset, [metric], transformers))
Even in the first pass, we see some overfitting from the model evaluation results.
{'training pearson_r2_score': 0.9203419837932797}{'testing pearson_r2_score': 0.7529095508565846}
Let’s see how to predict solubility for a new set of molecules:
smiles = ['COC(C)(C)CCCC(C)CC=CC(C)=CC(=O)OC(C)C','CCOC(=O)CC','CSc1nc(NC(C)C)nc(NC(C)C)n1','CC(C#C)N(C)C(=O)Nc1ccc(Cl)cc1','Cc1cc2ccccc2cc1C']
Next, we need to featurize these new set of molecules from their SMILES format
from rdkit import Chemmols = [Chem.MolFromSmiles(s) for s in smiles]featurizer = dc.feat.ConvMolFeaturizer()x = featurizer.featurize(mols)predicted_solubility = model.predict_on_batch(x)predicted_solubility
And thus, we can see the predicted solubility values :
array([[-0.45654652],       [ 1.5316172 ],       [ 0.19090167],       [ 0.44833142],       [-0.32875094]], dtype=float32)
We saw very easily how DeepChem makes it very easy for the above two usecases, which may require alot of time for a human chemist to solve these problem!
For the final part, we will see few visualizations and querying techniques available as a part of RDkit which is very much required when anyone is working for such use cases.
SMARTS is an extension of the SMILES language described previously that can be used to create queries.
# To gain a visual understanding of compounds in our dataset, let's draw them using rdkit. We define a couple of helper functions to get startedimport tempfilefrom rdkit import Chemfrom rdkit.Chem import Drawfrom itertools import islicefrom IPython.display import Image, displaydef display_images(filenames):    """Helper to pretty-print images."""    for file in filenames:          display(Image(file))def mols_to_pngs(mols, basename="test"):    """Helper to write RDKit mols to png files."""    filenames = []    for i, mol in enumerate(mols):        filename = "%s%d.png" % (basename, i)        Draw.MolToFile(mol, filename)        filenames.append(filename)    return filenames
Now, let’s take a sample SMILES string and visualize the molecular structure.
from rdkit import Chemfrom rdkit.Chem.Draw import MolsToGridImagesmiles_list = ["CCCCC","CCOCC","CCNCC","CCSCC"]mol_list = [Chem.MolFromSmiles(x) for x in smiles_list]display_images(mols_to_pngs(mol_list))
This is how the visual structures are formed from the SMILES string.
Now, let’s say we want to query SMILES string that has three adjacent carbons.
query = Chem.MolFromSmarts("CCC")match_list = [mol.GetSubstructMatch(query) for mol inmol_list]MolsToGridImage(mols=mol_list, molsPerRow=4,highlightAtomLists=match_list)
We see, that the highlighted part, represents the compound with three adjacent carbons.
Similarly, let’s see some wild character query and other sub-structure query options.
query = Chem.MolFromSmarts("C*C")match_list = [mol.GetSubstructMatch(query) for mol inmol_list]MolsToGridImage(mols=mol_list, molsPerRow=4,highlightAtomLists=match_list)
query = Chem.MolFromSmarts("C[C,N,O]C")match_list = [mol.GetSubstructMatch(query) for mol inmol_list]MolsToGridImage(mols=mol_list, molsPerRow=4,highlightAtomLists=match_list)
Thus, we can see that selective subquery can also be easily handled.
Thus, this brings us to the end of this article. I know this article was very high level and specifically targeted for Data Scientists and ML Researchers interested in Drug Discovery, especially during the time of an existing pandemic like Covid19. Hope I was able to help! If you are someone with a strong background in Bio-informatics or Chem-informatics and wants to venture into the world of data science, please reach out to me through any of the options mentioned here. Keep following: https://medium.com/@adib0073 and my website: https://www.aditya-bhattacharya.net/ for more!