From 1b46287d63ef0c7a16b2bb284b48ebdf4c15d517 Mon Sep 17 00:00:00 2001 From: FNTwin Date: Thu, 12 Dec 2024 08:20:00 -0800 Subject: [PATCH 1/4] [skip ci] readme update --- README.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1b1f02d..c0139b3 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,12 @@ Implementation of [Equivariant Flow Matching for Molecule Conformer Generation]( ET-Flow is a state-of-the-art generative model for generating small molecule conformations using equivariant transformers and flow matching. -### Install Etflow +### Install ET-flow We are now available on PyPI. Easily install the package using the following command: ```bash pip install etflow ``` -### Setup dev Environment -Run the following commands to setup the environment: -```bash -conda env create -n etflow -f env.yml -conda activate etflow -# to install the etflow package -python3 -m pip install -e . -``` ### Generating Conformations for Custom Smiles We have a sample notebook ([generate_confs.ipynb](generate_confs.ipynb)) to generate conformations for custom smiles input. One needs to pass the config and corresponding checkpoint path in order as additional inputs. @@ -34,6 +26,15 @@ We currently support the following configurations and checkpoint: - `qm9-o3` - `drugs-so3` +### Setup Dev Environment +Run the following commands to setup the environment: +```bash +conda env create -n etflow -f env.yml +conda activate etflow +# to install the etflow package +python3 -m pip install -e . +``` + ### Preprocessing Data To pre-process the data, perform the following steps, 1. Download the raw GEOM data and unzip the raw data using the following commands, From f66579f64360eea28402230d25f29ab0bbdc98fa Mon Sep 17 00:00:00 2001 From: FNTwin Date: Sun, 15 Dec 2024 20:44:30 -0800 Subject: [PATCH 2/4] Fix conformers creation in predict. Return 1 mol n confs --- etflow/commons/covmat.py | 7 +- etflow/models/model.py | 11 +- tutorial.ipynb | 469 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 465 insertions(+), 22 deletions(-) diff --git a/etflow/commons/covmat.py b/etflow/commons/covmat.py index a021b67..0af74f9 100644 --- a/etflow/commons/covmat.py +++ b/etflow/commons/covmat.py @@ -33,11 +33,12 @@ def set_rdmol_positions(rdkit_mol, pos): """ Args: rdkit_mol: An `rdkit.Chem.rdchem.Mol` object. - pos: (N_atoms, 3) + pos: (n, 3, N_atoms) """ mol = deepcopy(rdkit_mol) - conformer = build_conformer(pos) - mol.AddConformer(conformer) + for conf_pos in pos: + conformer = build_conformer(conf_pos) + mol.AddConformer(conformer) return mol diff --git a/etflow/models/model.py b/etflow/models/model.py index b7160e3..114245a 100644 --- a/etflow/models/model.py +++ b/etflow/models/model.py @@ -1,4 +1,3 @@ -from copy import deepcopy from typing import Any, Dict, List, Optional, TypeVar import numpy as np @@ -706,13 +705,9 @@ def sample( ) if as_mol: mol = get_mol_from_smiles(smile) - set_rdmol_positions(mol, pos[0]) - mols = [] - for i in range(num_samples): - copied_mol = deepcopy(mol) - set_rdmol_positions(copied_mol, pos[i]) - mols.append(copied_mol) - data[smile] = mols + data[smile] = set_rdmol_positions(mol, pos) + else: + data[smile] = pos return data diff --git a/tutorial.ipynb b/tutorial.ipynb index 6a27d3b..0cbc2b1 100644 --- a/tutorial.ipynb +++ b/tutorial.ipynb @@ -13,7 +13,7 @@ " This is the list of implemented interpolations {self.__interpolation_types__}.\\n\"\"\"\n", "/Users/cristian.gabellini/Desktop/workspace/ETFlow/etflow/models/model.py:176: SyntaxWarning: invalid escape sequence '\\I'\n", " This is the list of implemented interpolations {self.__path_types__}.\\n\"\"\"\n", - "\u001b[32m2024-12-12 00:37:56.328\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36metflow.utils\u001b[0m:\u001b[36minstantiate_model\u001b[0m:\u001b[36m137\u001b[0m - \u001b[1mLoading BaseFlow with args: {'network_type': 'TorchMDDynamics', 'hidden_channels': 160, 'num_layers': 20, 'num_rbf': 64, 'rbf_type': 'expnorm', 'trainable_rbf': True, 'activation': 'silu', 'neighbor_embedding': True, 'cutoff_lower': 0.0, 'cutoff_upper': 10.0, 'max_z': 100, 'node_attr_dim': 10, 'edge_attr_dim': 1, 'attn_activation': 'silu', 'num_heads': 8, 'distance_influence': 'both', 'reduce_op': 'sum', 'qk_norm': True, 'so3_equivariant': False, 'clip_during_norm': True, 'parity_switch': 'post_hoc', 'output_layer_norm': False, 'sigma': 0.1, 'prior_type': 'harmonic', 'interpolation_type': 'linear', 'optimizer_type': 'AdamW', 'lr': 0.0008, 'weight_decay': 1e-08, 'lr_scheduler_type': 'CosineAnnealingWarmupRestarts', 'first_cycle_steps': 375000, 'cycle_mult': 1.0, 'max_lr': 0.0005, 'min_lr': 1e-08, 'warmup_steps': 0, 'gamma': 0.05, 'last_epoch': -1, 'lr_scheduler_monitor': 'val/loss', 'lr_scheduler_interval': 'step', 'lr_scheduler_frequency': 1}\u001b[0m\n" + "\u001b[32m2024-12-15 20:33:45.785\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36metflow.utils\u001b[0m:\u001b[36minstantiate_model\u001b[0m:\u001b[36m137\u001b[0m - \u001b[1mLoading BaseFlow with args: {'network_type': 'TorchMDDynamics', 'hidden_channels': 160, 'num_layers': 20, 'num_rbf': 64, 'rbf_type': 'expnorm', 'trainable_rbf': True, 'activation': 'silu', 'neighbor_embedding': True, 'cutoff_lower': 0.0, 'cutoff_upper': 10.0, 'max_z': 100, 'node_attr_dim': 10, 'edge_attr_dim': 1, 'attn_activation': 'silu', 'num_heads': 8, 'distance_influence': 'both', 'reduce_op': 'sum', 'qk_norm': True, 'so3_equivariant': False, 'clip_during_norm': True, 'parity_switch': 'post_hoc', 'output_layer_norm': False, 'sigma': 0.1, 'prior_type': 'harmonic', 'interpolation_type': 'linear', 'optimizer_type': 'AdamW', 'lr': 0.0008, 'weight_decay': 1e-08, 'lr_scheduler_type': 'CosineAnnealingWarmupRestarts', 'first_cycle_steps': 375000, 'cycle_mult': 1.0, 'max_lr': 0.0005, 'min_lr': 1e-08, 'warmup_steps': 0, 'gamma': 0.05, 'last_epoch': -1, 'lr_scheduler_monitor': 'val/loss', 'lr_scheduler_interval': 'step', 'lr_scheduler_frequency': 1}\u001b[0m\n" ] }, { @@ -21,7 +21,7 @@ "output_type": "stream", "text": [ "Loading drugs-o3 from config\n", - "Checkpoint found at cache/drugs-o3.ckpt\n", + "Checkpoint found at /Users/cristian.gabellini/Desktop/workspace/ETFlow/cache/drugs-o3.ckpt\n", "Device cuda not found. Using cpu instead\n" ] }, @@ -30,36 +30,483 @@ "output_type": "stream", "text": [ ":472: SyntaxWarning: invalid escape sequence '\\m'\n", - "/Users/cristian.gabellini/Desktop/workspace/ETFlow/etflow/models/model.py:214: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", + "/Users/cristian.gabellini/Desktop/workspace/ETFlow/etflow/models/model.py:215: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.\n", " checkpoint = torch.load(checkpoint_path, map_location=device)\n", "Seed set to 42\n", "/Users/cristian.gabellini/Desktop/workspace/ETFlow/etflow/commons/utils.py:177: UserWarning: torch.sparse.SparseTensor(indices, values, shape, *, device=) is deprecated. Please use torch.sparse_coo_tensor(indices, values, shape, dtype=, device=). (Triggered internally at /Users/runner/work/_temp/anaconda/conda-bld/pytorch_1724788636709/work/torch/csrc/utils/tensor_new.cpp:643.)\n", " bgraph_adj = torch.sparse.LongTensor(edge_index, edge_type, torch.Size([N, N]))\n" ] + } + ], + "source": [ + "from etflow import BaseFlow\n", + "model=BaseFlow.from_default(model=\"drugs-o3\", cache=\"/Users/cristian.gabellini/Desktop/workspace/ETFlow/cache/\")\n", + "smiles=model.predict(['CN1C=NC2=C1C(=O)N(C(=O)N2C)C'], num_samples=3, as_mol=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from etflow.commons.covmat import set_rdmol_positions, build_conformer\n", + "from etflow.commons.featurization import MoleculeFeaturizer, get_mol_from_smiles\n", + "mol = get_mol_from_smiles('CN1C=NC2=C1C(=O)N(C(=O)N2C)C')\n", + "mol2=set_rdmol_positions(mol,smiles['CN1C=NC2=C1C(=O)N(C(=O)N2C)C'][0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from copy import deepcopy\n", + "def set_rdmol_positions(rdkit_mol, pos):\n", + " mol = deepcopy(rdkit_mol)\n", + " for conf in pos:\n", + " conformer = build_conformer(pos)\n", + " mol.AddConformer(conformer)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(smiles['CN1C=NC2=C1C(=O)N(C(=O)N2C)C'])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "application/3dmoljs_load.v0": "
\n

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n
\n", + "text/html": [ + "
\n", + "

3Dmol.js failed to load for some reason. Please check your browser console for error messages.

\n", + "
\n", + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { + "image/png": "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efPY2Fij0Thx4sTTp09z7wgieigGIT1EgwYN7peIFSNrVE/E9PT0p59+etiwYWlpae3bt9+/f398fLy3t7e6VRGRXTAIIdSuge4rMzOzrKwMgIODg/lbn9++fTs3N1c69vPzk71vLDU19fvvv1+9evXevXulfz8eHh59+vSJiooaNmzYA16uVq1a0qbBvr6+165dM/PlXnzxxS+//FI63rVrV1hY2N1/WlZWNn/+/HfeeScvL6969eqzZ89++eWXbX+1VSKyHQxCqrr/TcTq1asPGzYsIiJiwIAB/5uIsgfh7t27//KXv5w4cQJAeHj4F198Ua9evUf/vohIV9g0SlX3v62md+7cWbJkybBhw/z9/aOiotatW1dcXKzES9+6dWvatGm9evU6ceJEkyZNfv7553Xr1jEFiagKGIQkg4pEvHjxopSIt2/f/kMilpSUyPJa0gTBkJCQefPmOTo6RkdHnzhxYuDAgbLcnIh0iE2jpIiUlJQffvhh9erVe/bskX6nRo0a1apVq1Gjho+PT61atdasWWPmrT755JMNGzZIx2+88UZcXNzmzZsB9OrV64svvmjevLkS9RORfjAISVn3TERp74uBAwe6uLiYeZ/CwsLY2NiYmJji4mIfH58PPvjgxRdfrFg9nIioyhiEZCWPkohbt26dPHnymTNnDAbDuHHj5syZU7t2batUTUTaxyAka7t06dLatWsfmojXr1/39fXNzMyMjo5esmQJgDZt2vzrX//q2rWraqUTkRYxCEk1/5uINWvWDA8PHzVq1GuvvXb58uU5c+a88847d+7c8fDwePPNN99++23zm1KJiMzEICT1nT59etWqVatXr5ZmBAJwcnKSVhIAMGLEiHnz5gUFBalXIBFpGYOQbMjdz4g+Pj5CiIULFz799NNq10VEWsYgJFs0ffr0Tz75ZOrUqXPnzlW7FiLSOE6oJ1vUsWNHAJmZmWoXQkTaxyAkW1S/fn0AaWlpahdCRNrHICRb1KBBAwCpqalqF0JE2sc+QrJFRqPR3d29tLS0oKDAzc1N7XKISMv4REi2SNp/UQhx5coVtWshIo1jEJKNYjchEVkHg5BsFIOQiKyDQUg2iuNliMg6GIRko6Q11S5fvqx2IUSkcQxCslFsGiUi62AQko1i0ygRWQfnEZKNKigo8PT0dHNzKygo4E70RKQcPhGSjfLw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", + "image/svg+xml": [ + "\n", + "\n", + "\n", + " \n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/html": [], "text/plain": [ - "{'CN1C=NC2=C1C(=O)N(C(=O)N2C)C': [,\n", - " ,\n", - " ]}" + "" ] }, - "execution_count": 1, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "from etflow import BaseFlow\n", - "model=BaseFlow.from_default(model=\"drugs-o3\")\n", - "model.predict(['CN1C=NC2=C1C(=O)N(C(=O)N2C)C'], num_samples=3, as_mol=True)" + "import py3Dmol # might have to pip install this for viz\n", + "from rdkit.Chem.Draw import IPythonConsole\n", + "IPythonConsole.molSize = (600, 600) # Change image size\n", + "IPythonConsole.ipython_useSVG = True # Change output to SVG\n", + "IPythonConsole.ipython_3d = True\n", + "mol2" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{}" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "smiles" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "etflow", + "display_name": "Python 3", "language": "python", "name": "python3" }, From df52dabc46ab5d54ba217ff929fb6279e60afb8a Mon Sep 17 00:00:00 2001 From: FNTwin Date: Sun, 15 Dec 2024 23:52:06 -0500 Subject: [PATCH 3/4] Docstrings fix --- etflow/commons/covmat.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etflow/commons/covmat.py b/etflow/commons/covmat.py index 0af74f9..477f2ce 100644 --- a/etflow/commons/covmat.py +++ b/etflow/commons/covmat.py @@ -33,7 +33,7 @@ def set_rdmol_positions(rdkit_mol, pos): """ Args: rdkit_mol: An `rdkit.Chem.rdchem.Mol` object. - pos: (n, 3, N_atoms) + pos: (n, N_atoms, 3) """ mol = deepcopy(rdkit_mol) for conf_pos in pos: From 50d64d60d69cbe34722a2036f17b419ad6716b89 Mon Sep 17 00:00:00 2001 From: FNTwin Date: Sun, 15 Dec 2024 23:54:57 -0500 Subject: [PATCH 4/4] Separate multiple to single set --- etflow/commons/covmat.py | 14 +++++++++++++- etflow/models/model.py | 4 ++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/etflow/commons/covmat.py b/etflow/commons/covmat.py index 477f2ce..b2345b8 100644 --- a/etflow/commons/covmat.py +++ b/etflow/commons/covmat.py @@ -29,7 +29,7 @@ def build_conformer(pos): return conformer -def set_rdmol_positions(rdkit_mol, pos): +def set_multiple_rdmol_positions(rdkit_mol, pos): """ Args: rdkit_mol: An `rdkit.Chem.rdchem.Mol` object. @@ -42,6 +42,18 @@ def set_rdmol_positions(rdkit_mol, pos): return mol +def set_rdmol_positions(rdkit_mol, pos): + """ + Args: + rdkit_mol: An `rdkit.Chem.rdchem.Mol` object. + pos: (N_atoms, 3) + """ + mol = deepcopy(rdkit_mol) + conformer = build_conformer(pos) + mol.AddConformer(conformer) + return mol + + def get_best_rmsd(probe, ref, use_alignmol=False): probe = RemoveHs(probe) ref = RemoveHs(ref) diff --git a/etflow/models/model.py b/etflow/models/model.py index 114245a..054e77a 100644 --- a/etflow/models/model.py +++ b/etflow/models/model.py @@ -7,7 +7,7 @@ from torch_geometric.data import Batch from etflow.commons.configs import CONFIG_DICT -from etflow.commons.covmat import set_rdmol_positions +from etflow.commons.covmat import set_multiple_rdmol_positions from etflow.commons.featurization import MoleculeFeaturizer, get_mol_from_smiles from etflow.commons.utils import signed_volume from etflow.models.base import BaseModel @@ -705,7 +705,7 @@ def sample( ) if as_mol: mol = get_mol_from_smiles(smile) - data[smile] = set_rdmol_positions(mol, pos) + data[smile] = set_multiple_rdmol_positions(mol, pos) else: data[smile] = pos return data