Created
June 4, 2022 12:41
-
-
Save iwatobipen/cb1d19ce90e3a73aa2d2bdaa62cff69c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"> **How to run this notebook (command-line)?**\n", | |
"1. Install the `ReinventCommunity` environment:\n", | |
"`conda env create -f environment.yml`\n", | |
"2. Activate the environment:\n", | |
"`conda activate ReinventCommunity`\n", | |
"3. Execute `jupyter`:\n", | |
"`jupyter notebook`\n", | |
"4. Copy the link to a browser" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# `Link-INVENT`: Reinforcement Learning\n", | |
"\n", | |
"This tutorial notebook demonstrates how to run `Link-INVENT`, with emphasis on the parameters that are most relevant for practical applications. The example shown is based on the `Illustrative Example` presented in the `Link-INVENT` manuscript.\n", | |
"\n", | |
"Specifically, the objective is as follows:\n", | |
"\n", | |
"Link 2 benzene rings such that the:\n", | |
"1. Linker contains as few hydrogen-bond donors as possible (give the linker maximum reward if there are 0 hydrogen-bond donors)\n", | |
"2. Linker contains exactly 1 ring\n", | |
"\n", | |
"The training plot will look similar to below:\n", | |
"\n", | |
"![](img/LinkINVENT_Example.png)\n", | |
"\n", | |
"One can see that the `Link-INVENT` agent gradually learns to satisfy the desired objective. Example linked molecules are shown at different time-steps of the run to illustrate agent learning. At the end of the run, most of the generated molecules will satisfy the desired objective." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# load dependencies\n", | |
"import os\n", | |
"import re\n", | |
"import json\n", | |
"import tempfile\n", | |
"\n", | |
"# --------- change these path variables as required\n", | |
"reinvent_dir = os.path.expanduser(\"/home/iwatobipen/dev/reinvent-32/Reinvent/\")\n", | |
"reinvent_env = os.path.expanduser(\"/home/iwatobipen/miniconda3/envs/reinvent.v3.2/\")\n", | |
"output_dir = os.path.expanduser(\"/home/iwatobipen/dev/reinvent-32/Link-INVENT_demo\")\n", | |
"\n", | |
"# --------- do not change\n", | |
"# get the notebook's root path\n", | |
"try: ipynb_path\n", | |
"except NameError: ipynb_path = os.getcwd()\n", | |
"\n", | |
"# if required, generate a folder to store the results\n", | |
"try:\n", | |
" os.mkdir(output_dir)\n", | |
"except FileExistsError:\n", | |
" pass" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Setting up the configuration\n", | |
"The `REINVENT` platform (which provides access to `Link-INVENT`) has an entry point that loads a specified `JSON` file on startup. `JSON` is a low-level data format that allows to specify a fairly large number of parameters in a cascading fashion very quickly. The parameters are structured into *blocks* which can in turn contain blocks or simple values, such as *True* or *False*, strings and numbers. In this tutorial, we will go through the different blocks step-by-step, explaining their purpose and potential values for given parameters. Note, that while we will write out the configuration as a `JSON` file in the end, in Python we handle the same information as a simple `dict`." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 1. Run Type Block" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# initialize the dictionary\n", | |
"configuration = {\n", | |
" \"version\": 3,\n", | |
" \"model_type\": \"link_invent\",\n", | |
" \"run_type\": \"reinforcement_learning\"\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 2. Logging Block\n", | |
"This block specifies output directories for **logging** and **results**, containing the following information:\n", | |
"\n", | |
"* **logging**: saves the training progress of the `Link-INVENT` experiment. Visualizing the training log via `tensorboard` which is installed in the provided environment will allow one to monitor the agent's learning progress and to what extent each desired objective is optimized. The training progress can also be monitored during the run to potentially spot early training plateau, in which case, it may be useful to start a new run with different hyperparameters.\n", | |
"\n", | |
"\n", | |
"* **results**: saves the final results of the `Link-INVENT` experiment. This includes the `scaffold memory` (discussed further at the end of this notebook) which contains all the top scoring compounds generated throughout the run. This `CSV` file allows users to easily parse the top results for downstream processing." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# add block to specify whether to run locally or not and\n", | |
"# where to store the results and logging\n", | |
"configuration[\"logging\"] = {\n", | |
" \"sender\": \"\", # only relevant if \"recipient\" is set to \"remote\"\n", | |
" \"recipient\": \"local\", # either to local logging or use a remote REST-interface\n", | |
" \"logging_path\": os.path.join(output_dir, \"progress.log\"), # load this folder in tensorboard to \n", | |
" # visualize training progress\n", | |
" \"result_folder\": os.path.join(output_dir, \"results\"), # output directory for results\n", | |
" \"job_name\": \"Link-INVENT RL Demo\", # set an arbitrary job name for identification\n", | |
" \"job_id\": \"N/A\" # only relevant if \"recipient\" is set to \"remote\"\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"### 3. Parameters Block\n", | |
"\n", | |
"This block specifies all the experiment parameters. In the cell below, we first set the hyperparameters for `Reinforcement Learning (RL)`, including:\n", | |
"\n", | |
"1. `\"actor\" and \"critic\"`: These are the paths to a pre-trained `Link-INVENT` generative model. One such model is provided in the /models folder in this repository and named `linkinvent.prior`. This prior is the generative model featured in the `Link-INVENT` manuscript and all details related to its training can be found in the `Supporting Information`. Generally, the `\"actor\"` and `\"critic\"` are initialized as the same pre-trained model. \n", | |
"\n", | |
"\n", | |
"2. `\"warheads\"`: This is a list specifiying the 2 molecular sub-units (as SMILES) to link. The `\"*\"` denotes the attachment point position of each warhead and the warheads are separated using the `\"|\"` delimiter.\n", | |
"\n", | |
"\n", | |
"3. `\"n_steps\"`: This denotes how many epochs to run `Link-INVENT`. Typically this can be set to between 100-200. In the example below, 20 is used for the `Illustrative Example` as the objective is relatively simple and thus, the agent learns to generate linkers that satisfy the desired objective quickly.\n", | |
"\n", | |
"\n", | |
"4. `\"learning_rate\"`: This denotes the learning rate. Generally, the default 0.0001 works well.\n", | |
"\n", | |
"\n", | |
"5. `\"batch_size\"`: The number of linkers to generate per epoch. Generally, the default 128 works well.\n", | |
"\n", | |
"\n", | |
"6. `\"randomize_warhead\"`: Denotes whether to obtain a randomized SMILES representation of the warheads at every epoch. Generally, the default \"true\" works well. Randomizing SMILES increases the generalizability (results may cover a larger `chemical space`).\n", | |
"\n", | |
"7. `\"learning_strategy\"`: This denotes how the `loss function` is constructed. The default `\"dap\"` strategy and `\"sigma\" = 120 ` works well. For more information, see the `Link-INVENT` and `Lib-INVENT` manuscripts." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# add the \"parameters\" block\n", | |
"configuration[\"parameters\"] = {}\n", | |
"\n", | |
"configuration[\"parameters\"] = {\n", | |
" \"actor\": os.path.join(ipynb_path, \"models/linkinvent.prior\"), # this pre-trained prior is provided in /models\n", | |
" \"critic\": os.path.join(ipynb_path, \"models/linkinvent.prior\"),\n", | |
" \"warheads\" : [\"*c1ccccc1|*c1ccccc1\"],\n", | |
" \"n_steps\": 100, # number of epochs to run Link-INVENT\n", | |
" \"learning_rate\": 0.0001, # the default value works well but can be increased depending on training progress\n", | |
" \"batch_size\": 64, # the default value works well > 128 >>64 cuda memory issue\n", | |
" \"randomize_warheads\": True,\n", | |
" \"learning_strategy\": {\n", | |
" \"name\": \"dap\", \n", | |
" \"parameters\": {\n", | |
" \"sigma\": 120\n", | |
" }\n", | |
" }\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"#### Configure the scoring strategy\n", | |
"This includes setting up the `Diversity Filters` (discussed below) and the `Scoring Function` (discussed below)." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"configuration[\"parameters\"][\"scoring_strategy\"] = {\n", | |
" \"name\": \"link_invent\" # do not change\n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### Configure Diversity Filter\n", | |
"\n", | |
"The Diversity Filter (DF) offers users the control over agent `exploration` (generating molecules from different `chemical space`) and `exploitation` (generating favourable molecules from similar `chemical space`). There are 3 DFs available in `Link-INVENT`:\n", | |
"\n", | |
"\n", | |
"1. `\"IdenticalMurckoScaffold\"`: Penalizes repeated sampling of the same Bemis-Murcko scaffold. An important point to note here is that this effectively operates at the linker level since the 2 warheads are held constant. Thus, this DF ensures diverse linkers are generated.\n", | |
"\n", | |
"\n", | |
"2. `\"NoFilterWithPenalty\"`: Penalizes repeated sampling of the same linker. The corresponding linker receives a score scaled by 0.5 (halved).\n", | |
"\n", | |
"\n", | |
"3. `\"NoFilter\"`: No penalization.\n", | |
"\n", | |
"The notion of \"repeated sampling\" is governed by the `\"bucket_size\"` parameter. This denotes the maximum number of permitted linkers corresponding to the choice of DF used. Further sampling of the linker will be penalized. For example, if a linker Bemis-Murcko scaffold (denote it scaffold A) has been sampled 25 times using a `\"bucket_size\"` of 25, the 26th time scaffold A is sampled, the linker receives a score of 0. This in turn encourages the agent to explore other `chemical space`.\n", | |
"\n", | |
"Additional parameters include:\n", | |
"\n", | |
"\n", | |
"1. `\"minscore\"`: Denotes the mininum score a linker (and the corresponding linked molecules) must achieve to be saved in the final output (`scaffold memory`). In practice, this can be set to 0.4 so that only linkers that at least moderately satisfy the desired objective is saved. If set to 0, every single linker generated will be saved. This could be useful if one is interested in analyizing the overall sampling behaviour of the agent.\n", | |
"\n", | |
"\n", | |
"2. `\"minsimilarity\"`: If using the `\"IdenticalMurckoScaffold\"`, repeated sampling of the same Bemis-Murcko scaffold is penalized (as explained above). When a new Bemis-Murcko scaffold is generated by the agent, its similarity is compared to all the Bemis-Murcko scaffolds generated thus far. If there has already been a Bemis-Murcko scaffold sampled that possesses a similarity >= `\"minsimilarity\"`, the new Bemis-Murcko scaffold will populate that `bucket`. For example, consider a Bemis-Murcko scaffold A is sampled 24 times with a `\"bucket_size\"` of 25. Now consider a new (never seen before) Bemis-Murcko scaffold B is sampled. If B >= `\"minsimilarity\"`, then B will be added to the `bucket` of A. Subsequently, the next A or B sampled will result in 26 items in the bucket and would thus receive a score of 0 (penalization). This parameter can encourage more `exploration`." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"configuration[\"parameters\"][\"scoring_strategy\"][\"diversity_filter\"] = {\n", | |
" \"bucket_size\": 25,\n", | |
" \"minscore\": 0,\n", | |
" \"minsimilarity\": 0,\n", | |
" \"name\": \"IdenticalMurckoScaffold\" \n", | |
"}" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"##### Scoring Function Definition\n", | |
"The Scoring Function is the reward function used to assess the *desirability* of molecules generated by `Link-INVENT` via `RL`. An arbitrary number of components (as long as it is supported in the codebase) can be specified in the Scoring Function. Subsequently, the agent gradually learns to generate molecules that satisfy all desired objectives. \n", | |
"\n", | |
"An important consideration is that different components can have different ranges of raw values. These values are normalized in the interval $[0,1]$ such that the `Link-INVENT` agent can properly learn. Scores achieved by each component is aggregated to a `total score` desiring the overall *desirability* of the generated molecules. This is done either by the weighted average sum (`custom_sum`) or by a weighted geometric mean (`custom_product`). It is this `total score` that is used for the agent's policy update in the `RL` loop. For more details on `custom_sum` and `custom_product`, see the notebook in this repository: `Score_Transformations`.\n", | |
"\n", | |
"We now discuss how raw component values are normalized in the interval $[0,1]$. A `score transformation` is applied that transforms the raw values based on the defined function. Tuning the parameters of the transformation function allows one to control the agent's learning, e.g., one may be interested in generating molecules with < 500 MW (arbitrary example). One could specify the transformation function to give maximum reward to molecules that are indeed < 500 MW and lower reward (or no reward) otherwise. See the notebook in this repository: `Score_Transformations` for more information. " | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The Scoring Function components pertaining to the `Illustrative Example` presented in this notebook are specified in the below cell." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"scoring_function = {\n", | |
" \"name\": \"custom_product\", \n", | |
" \"parallel\": False, # do not change \n", | |
" \n", | |
" \"parameters\": [\n", | |
" {\n", | |
" \"weight\": 1,\n", | |
" \"component_type\": \"linker_num_hbd\", # component name: this specific component pertains to controlling \n", | |
" # the number of hydrogen-bond donors in the linker\n", | |
" \"name\": \"Linker Num HBD\", # this can be arbitrary and is used for user reference\n", | |
" \"specific_parameters\": {\n", | |
" \"transformation\": {\n", | |
" # the transformation here gives generated linked molecules \n", | |
" # maximum reward if there are 0 hydrogen-bond donors\n", | |
" # see the notebook: \"Score_Transformations\" for more details on the transformation function\n", | |
" \"high\": 6,\n", | |
" \"low\": 0,\n", | |
" \"transformation_type\": \"reverse_sigmoid\",\n", | |
" \"k\": 0.15\n", | |
" }\n", | |
" }\n", | |
" }, {\n", | |
" \"weight\": 1,\n", | |
" \"component_type\": \"linker_num_rings\",\n", | |
" \"name\": \"Linker Num Rings\",\n", | |
" \"specific_parameters\": {\n", | |
" \"transformation\": {\n", | |
" # the transformation here simply gives the generated linked molecules\n", | |
" # a perfect reward (1) if the linker contains exactly 1 ring, otherwise 0 reward\n", | |
" \"high\": 3,\n", | |
" \"low\": 2,\n", | |
" \"transformation_type\": \"step\"\n", | |
" }\n", | |
" }\n", | |
" },{\n", | |
" \"weight\": 1,\n", | |
" \"component_type\": \"linker_graph_length\",\n", | |
" \"name\": \"Linker Graph Length\",\n", | |
" \"specific_parameters\": {\n", | |
" \"transformation\": {\n", | |
" # the transformation here simply gives the generated linked molecules\n", | |
" # a perfect reward (1) if the linker contains exactly 1 ring, otherwise 0 reward\n", | |
" \"high\": 20,\n", | |
" \"low\": 8,\n", | |
" \"transformation_type\": \"reverse_sigmoid\",\n", | |
" \"k\": 0.15\n", | |
" }\n", | |
" }\n", | |
" \n", | |
" } ]\n", | |
"}\n", | |
"\n", | |
"configuration[\"parameters\"][\"scoring_strategy\"][\"scoring_function\"] = scoring_function" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The dictionary has now been initialized with all parameters necessary to run `Link-INVENT`. Next, we write it out as a `JSON` which will serve as the `Configuration JSON` to run `Link-INVENT`." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"/home/iwatobipen/dev/reinvent-32/Link-INVENT_demo/Link-INVENT_Configuration.json\n" | |
] | |
} | |
], | |
"source": [ | |
"# write out the configuration to disc\n", | |
"configuration_JSON_path = os.path.join(output_dir, \"Link-INVENT_Configuration.json\")\n", | |
"print(configuration_JSON_path)\n", | |
"with open(configuration_JSON_path, 'w') as f:\n", | |
" json.dump(configuration, f, indent=4, sort_keys=False)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"The `Configuration JSON` is saved to the `output_dir` specified in the beginning of this notebook." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Run\n", | |
"Execute `Link-INVENT` directly in this jupyter notebook" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"%%capture captured_err_stream --no-stderr\n", | |
"\n", | |
"# execute REINVENT from the command-line\n", | |
"!{reinvent_env}/bin/python {reinvent_dir}/input.py {configuration_JSON_path}" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 10, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"# print the output to a file, just to have it for documentation\n", | |
"with open(os.path.join(output_dir, \"run.err\"), 'w') as file:\n", | |
" file.write(captured_err_stream.stdout)" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Execute in command line\n", | |
"```\n", | |
"# activate environment\n", | |
"$ conda activate reinvent.v3.2\n", | |
"\n", | |
"# execute in command line\n", | |
"$ python <reinvent_dir>/input.py <configuration_JSON_path>\n", | |
"```" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Analyse the results\n", | |
"\n", | |
"In order to analyze the run in a more intuitive way, we can use `tensorboard`:\n", | |
"\n", | |
"```\n", | |
"# go to the root folder of the output\n", | |
"$ cd <output_dir>\n", | |
"\n", | |
"# activate the environment\n", | |
"$ conda activate reinvent.v3.2\n", | |
"\n", | |
"# start tensorboard\n", | |
"$ tensorboard --logdir \"progress.log\"\n", | |
"```\n", | |
"\n", | |
"Then copy the link provided to a browser window. The following figures are example plots - there is always some randomness involved. The `tensorboard` plots display both the individual scoring function components and the average overall score." | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"![](img/Link-INVENT_Training_Plots.png)\n", | |
"The 2 components in the scoring function, `linker number of hydrogen-bond donors` (which we want to limit in the `Illustrative Example`) and the `linker number of rings` (which we want to be exactly 1) are satisfied very quickly, as exemplified by the rapid score increase. The `Average score (total score)` plot is the aggregated score of the 2 components via the `custom product` (weighted geometric mean)\n", | |
"![](img/Link-INVENT_Training_Plots_2.png)\n", | |
"Valid SMILES are SMILES that follow correct chemical syntax (if it can be parsed by RDKit). Number of SMILES found shows SMILES with scores over 0.4 (or other `min_score` specified in the DF setup if required. **In this notebook, this was set to 0 so all SMILES generated were collected**).\n" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"## Scaffold Memory: where the top compounds generated are saved\n", | |
"All valid compounds with scores over 0.4 (**In this notebook, this was set to 0 so all SMILES generated were collected**) can be found in the `scaffold_memory.csv` file.The SMILES are ranked by their total scores from high to low. \n", | |
"\n", | |
"**note: scaffold_memory.csv contains SMILES, Scaffolds, Scores from different components and Total score.**" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"First, we show a few lines of the `scaffold_memory.csv`." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 11, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/html": [ | |
"<div>\n", | |
"<style scoped>\n", | |
" .dataframe tbody tr th:only-of-type {\n", | |
" vertical-align: middle;\n", | |
" }\n", | |
"\n", | |
" .dataframe tbody tr th {\n", | |
" vertical-align: top;\n", | |
" }\n", | |
"\n", | |
" .dataframe thead th {\n", | |
" text-align: right;\n", | |
" }\n", | |
"</style>\n", | |
"<table border=\"1\" class=\"dataframe\">\n", | |
" <thead>\n", | |
" <tr style=\"text-align: right;\">\n", | |
" <th></th>\n", | |
" <th>Step</th>\n", | |
" <th>Scaffold</th>\n", | |
" <th>SMILES</th>\n", | |
" <th>Linker Num HBD</th>\n", | |
" <th>Linker Num Rings</th>\n", | |
" <th>Linker Graph Length</th>\n", | |
" <th>raw_Linker Num HBD</th>\n", | |
" <th>raw_Linker Num Rings</th>\n", | |
" <th>raw_Linker Graph Length</th>\n", | |
" <th>total_score</th>\n", | |
" <th>ID</th>\n", | |
" </tr>\n", | |
" </thead>\n", | |
" <tbody>\n", | |
" <tr>\n", | |
" <th>0</th>\n", | |
" <td>34.0</td>\n", | |
" <td>c1ccc(Cc2nncn3cc(-c4ccccc4)cc23)cc1</td>\n", | |
" <td>c1ccc(Cc2nncn3cc(-c4ccccc4)cc23)cc1</td>\n", | |
" <td>0.84902</td>\n", | |
" <td>1.0</td>\n", | |
" <td>0.94676</td>\n", | |
" <td>0.0</td>\n", | |
" <td>2.0</td>\n", | |
" <td>4.0</td>\n", | |
" <td>0.929792</td>\n", | |
" <td>default_job_0</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>1</th>\n", | |
" <td>98.0</td>\n", | |
" <td>c1ccc(-c2ncc3c(-c4ccccc4)cnn3n2)cc1</td>\n", | |
" <td>c1ccc(-c2ncc3c(-c4ccccc4)cnn3n2)cc1</td>\n", | |
" <td>0.84902</td>\n", | |
" <td>1.0</td>\n", | |
" <td>0.94676</td>\n", | |
" <td>0.0</td>\n", | |
" <td>2.0</td>\n", | |
" <td>4.0</td>\n", | |
" <td>0.929792</td>\n", | |
" <td>default_job_1</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>2</th>\n", | |
" <td>27.0</td>\n", | |
" <td>O=c1c(-c2ccccc2)cnc2n1CC(c1ccccc1)C2</td>\n", | |
" <td>O=c1c(-c2ccccc2)cnc2n1CC(c1ccccc1)C2</td>\n", | |
" <td>0.84902</td>\n", | |
" <td>1.0</td>\n", | |
" <td>0.94676</td>\n", | |
" <td>0.0</td>\n", | |
" <td>2.0</td>\n", | |
" <td>4.0</td>\n", | |
" <td>0.929792</td>\n", | |
" <td>default_job_2</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>3</th>\n", | |
" <td>83.0</td>\n", | |
" <td>c1ccc(-c2cc3c(-c4ccccc4)nncn3n2)cc1</td>\n", | |
" <td>c1ccc(-c2cc3c(-c4ccccc4)nncn3n2)cc1</td>\n", | |
" <td>0.84902</td>\n", | |
" <td>1.0</td>\n", | |
" <td>0.94676</td>\n", | |
" <td>0.0</td>\n", | |
" <td>2.0</td>\n", | |
" <td>4.0</td>\n", | |
" <td>0.929792</td>\n", | |
" <td>default_job_3</td>\n", | |
" </tr>\n", | |
" <tr>\n", | |
" <th>4</th>\n", | |
" <td>16.0</td>\n", | |
" <td>c1ccc(-c2cnc3c(-c4ccccc4)cnn3c2)cc1</td>\n", | |
" <td>Cc1c(-c2ccccc2)cnc2c(-c3ccccc3)cnn12</td>\n", | |
" <td>0.84902</td>\n", | |
" <td>1.0</td>\n", | |
" <td>0.94676</td>\n", | |
" <td>0.0</td>\n", | |
" <td>2.0</td>\n", | |
" <td>4.0</td>\n", | |
" <td>0.929792</td>\n", | |
" <td>default_job_4</td>\n", | |
" </tr>\n", | |
" </tbody>\n", | |
"</table>\n", | |
"</div>" | |
], | |
"text/plain": [ | |
" Step Scaffold \\\n", | |
"0 34.0 c1ccc(Cc2nncn3cc(-c4ccccc4)cc23)cc1 \n", | |
"1 98.0 c1ccc(-c2ncc3c(-c4ccccc4)cnn3n2)cc1 \n", | |
"2 27.0 O=c1c(-c2ccccc2)cnc2n1CC(c1ccccc1)C2 \n", | |
"3 83.0 c1ccc(-c2cc3c(-c4ccccc4)nncn3n2)cc1 \n", | |
"4 16.0 c1ccc(-c2cnc3c(-c4ccccc4)cnn3c2)cc1 \n", | |
"\n", | |
" SMILES Linker Num HBD Linker Num Rings \\\n", | |
"0 c1ccc(Cc2nncn3cc(-c4ccccc4)cc23)cc1 0.84902 1.0 \n", | |
"1 c1ccc(-c2ncc3c(-c4ccccc4)cnn3n2)cc1 0.84902 1.0 \n", | |
"2 O=c1c(-c2ccccc2)cnc2n1CC(c1ccccc1)C2 0.84902 1.0 \n", | |
"3 c1ccc(-c2cc3c(-c4ccccc4)nncn3n2)cc1 0.84902 1.0 \n", | |
"4 Cc1c(-c2ccccc2)cnc2c(-c3ccccc3)cnn12 0.84902 1.0 \n", | |
"\n", | |
" Linker Graph Length raw_Linker Num HBD raw_Linker Num Rings \\\n", | |
"0 0.94676 0.0 2.0 \n", | |
"1 0.94676 0.0 2.0 \n", | |
"2 0.94676 0.0 2.0 \n", | |
"3 0.94676 0.0 2.0 \n", | |
"4 0.94676 0.0 2.0 \n", | |
"\n", | |
" raw_Linker Graph Length total_score ID \n", | |
"0 4.0 0.929792 default_job_0 \n", | |
"1 4.0 0.929792 default_job_1 \n", | |
"2 4.0 0.929792 default_job_2 \n", | |
"3 4.0 0.929792 default_job_3 \n", | |
"4 4.0 0.929792 default_job_4 " | |
] | |
}, | |
"execution_count": 11, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# import needed packages\n", | |
"import pandas as pd\n", | |
"\n", | |
"scaffold_memory_path = os.path.join(output_dir, 'results/scaffold_memory.csv')\n", | |
"df = pd.read_csv(scaffold_memory_path)\n", | |
"df.head()" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Next, we show a few example molecules." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 12, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "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\n", | |
"text/plain": [ | |
"<PIL.PngImagePlugin.PngImageFile image mode=RGB size=600x400 at 0x7F4481C52510>" | |
] | |
}, | |
"execution_count": 12, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"# import needed packages\n", | |
"from rdkit import Chem\n", | |
"from rdkit.Chem import Draw\n", | |
"\n", | |
"smile_list = df['SMILES'][:6].to_list() # change the number here to show more/less top compounds\n", | |
"mols = [Chem.MolFromSmiles(smiles) for smiles in smile_list]\n", | |
"Draw.MolsToGridImage(mols)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"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.7.7" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi,
Thanks for this notebook. Unfortunately, I'm getting an error while reproducing it - Can you help me in sorting out this error while executing the command - $ python <reinvent_dir>/input.py <configuration_JSON_path>:
environmental_variables = self.base_configuration["ENVIRONMENTAL_VARIABLES"]
KeyError: 'ENVIRONMENTAL_VARIABLES'
Could you please share any specific instructions or examples available to update the configuration file, if it's related to it?