diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c419263..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-cayman \ No newline at end of file diff --git a/ecnet/__init__.py b/ecnet/__init__.py index ce53add..017f38b 100644 --- a/ecnet/__init__.py +++ b/ecnet/__init__.py @@ -1 +1,2 @@ from .model import ECNet +__version__ = '4.1.0' diff --git a/ecnet/model.py b/ecnet/model.py index dd1d244..a766419 100644 --- a/ecnet/model.py +++ b/ecnet/model.py @@ -61,7 +61,8 @@ def fit(self, smiles: List[str] = None, target_vals: List[List[float]] = None, dataset: QSPRDataset = None, backend: str = 'padel', batch_size: int = 32, epochs: int = 100, lr_decay: float = 0.0, valid_size: float = 0.0, valid_eval_iter: int = 1, patience: int = 16, verbose: int = 0, - random_state: int = None, **kwargs) -> Tuple[List[float], List[float]]: + random_state: int = None, shuffle: bool = False, + **kwargs) -> Tuple[List[float], List[float]]: """ fit: fits ECNet to either (1) SMILES and target values, or (2) a pre-loaded QSPRDataset; the training process utilizes the Adam optimization algorithm, MSE loss, ReLU activation @@ -90,6 +91,8 @@ def fit(self, smiles: List[str] = None, target_vals: List[List[float]] = None, verbose (int, optional): if > 0, will print every `this` epochs; default = 0 random_state (int, optional): random_state used by sklearn.model_selection. train_test_split; default = None + shuffle (bool, optional): if True, shuffles training/validation data between epochs; + default = False; random_state should be None **kwargs: arguments accepted by torch.optim.Adam (i.e. learning rate, beta values) Returns: @@ -136,6 +139,18 @@ def fit(self, smiles: List[str] = None, target_vals: List[List[float]] = None, if not CBO.on_epoch_begin(epoch): break + if shuffle: + index_train, index_valid = train_test_split( + [i for i in range(len(dataset))], test_size=valid_size, + random_state=random_state + ) + dataloader_train = DataLoader( + Subset(dataset, index_train), batch_size=batch_size, shuffle=True + ) + dataloader_valid = DataLoader( + Subset(dataset, index_valid), batch_size=len(index_valid), shuffle=True + ) + train_loss = 0.0 self.train() diff --git a/ecnet/tasks/__init__.py b/ecnet/tasks/__init__.py index 2a1233d..de6541f 100644 --- a/ecnet/tasks/__init__.py +++ b/ecnet/tasks/__init__.py @@ -1,2 +1,3 @@ from .feature_selection import select_rfr -from .parameter_tuning import tune_batch_size, tune_model_architecture, tune_training_parameters +from .parameter_tuning import N_TESTS, CONFIG, tune_batch_size, tune_model_architecture,\ + tune_training_parameters diff --git a/ecnet/tasks/parameter_tuning.py b/ecnet/tasks/parameter_tuning.py index e8365cc..266c981 100644 --- a/ecnet/tasks/parameter_tuning.py +++ b/ecnet/tasks/parameter_tuning.py @@ -1,17 +1,19 @@ from ecabc import ABC from sklearn.metrics import median_absolute_error from copy import deepcopy +import numpy as np from ..model import ECNet from ..datasets.structs import QSPRDataset from typing import Iterable +N_TESTS = 10 CONFIG = { 'training_params_range': { - 'lr': (0.0, 0.05), - 'lr_decay': (0.0, 0.0001) + 'lr': (1e-16, 0.05), + 'lr_decay': (1e-16, 0.0001) }, 'architecture_params_range': { 'hidden_dim': (1, 1024), @@ -38,6 +40,8 @@ def _get_kwargs(**kwargs): 'eval_ds': kwargs.get('eval_ds'), 'epochs': kwargs.get('epochs', 100), 'batch_size': kwargs.get('batch_size', 32), + 'valid_size': kwargs.get('valid_size', 0.2), + 'patience': kwargs.get('patience', 32), 'lr_decay': kwargs.get('lr_decay', 0.0), 'lr': kwargs.get('lr', 0.001), 'beta_1': kwargs.get('beta_1', 0.9), @@ -54,6 +58,8 @@ def _get_kwargs(**kwargs): def _evaluate_model(trial_spec: dict) -> float: """ Training sub-function for cost functions _cost_batch_size, _cost_arch, _cost_train_hp; + Each model configuration is tested ecnet.tasks.parameter_tuning.N_TESTS times, average + median absolute error across all tests returned; default 10 tests per configuration Args: trial_spec (dict): all relevant parameters for this training trial @@ -62,25 +68,32 @@ def _evaluate_model(trial_spec: dict) -> float: float: median absolute error for dataset being evaluated (trial_spec['eval_ds']) """ - model = deepcopy(trial_spec['model']) - model._hidden_dim = trial_spec['hidden_dim'] - model._n_hidden = trial_spec['n_hidden'] - model._dropout = trial_spec['dropout'] - model._construct() - model.fit( - dataset=trial_spec['train_ds'], - epochs=trial_spec['epochs'], - batch_size=trial_spec['batch_size'], - lr_decay=trial_spec['lr_decay'], - lr=trial_spec['lr_decay'], - betas=(trial_spec['beta_1'], trial_spec['beta_2']), - eps=trial_spec['eps'], - weight_decay=trial_spec['weight_decay'], - amsgrad=trial_spec['amsgrad'] + model = ECNet( + trial_spec['train_ds'].desc_vals.shape[1], + trial_spec['train_ds'].target_vals.shape[1], + trial_spec['hidden_dim'], + trial_spec['n_hidden'], + trial_spec['dropout'] ) - yhat_eval = model(trial_spec['eval_ds'].desc_vals).detach().numpy() - y_eval = trial_spec['eval_ds'].target_vals - return median_absolute_error(y_eval, yhat_eval) + maes = [] + for _ in range(N_TESTS): + model._construct() + model.fit( + dataset=trial_spec['train_ds'], + epochs=trial_spec['epochs'], + batch_size=trial_spec['batch_size'], + patience=trial_spec['patience'], + lr_decay=trial_spec['lr_decay'], + lr=trial_spec['lr_decay'], + betas=(trial_spec['beta_1'], trial_spec['beta_2']), + eps=trial_spec['eps'], + weight_decay=trial_spec['weight_decay'], + amsgrad=trial_spec['amsgrad'] + ) + yhat_eval = model(trial_spec['eval_ds'].desc_vals).detach().numpy() + y_eval = trial_spec['eval_ds'].target_vals + maes.append(median_absolute_error(y_eval, yhat_eval)) + return np.mean(maes) def _cost_batch_size(vals: Iterable[float], **kwargs) -> float: @@ -100,20 +113,43 @@ def _cost_batch_size(vals: Iterable[float], **kwargs) -> float: return _evaluate_model(trial_spec) -def tune_batch_size(n_bees: int, n_iter: int, n_processes: int = 1, **kwargs) -> dict: +def tune_batch_size(n_bees: int, n_iter: int, dataset_train: QSPRDataset, + dataset_eval: QSPRDataset, n_processes: int = 1, + **kwargs) -> dict: """ - Tunes the batch size during training + Tunes the batch size during training; additional **kwargs can include any in: + [ + # ECNet parameters + 'epochs' (default 100), + 'valid_size' (default 0.2), + 'patience' (default 32), + 'lr_decay' (default 0.0), + 'hidden_dim' (default 128), + 'n_hidden' (default 2), + 'dropout': (default 0.0), + # Adam optim. alg. arguments + 'lr' (default 0.001), + 'beta_1' (default 0.9), + 'beta_2' (default 0.999), + 'eps' (default 1e-8), + 'weight_decay' (default 0.0), + 'amsgrad' (default False) + ] Args: n_bees (int): number of employer bees to use in ABC algorithm n_iter (int): number of iterations, or "search cycles", for ABC algorithm - n_processes (int): if > 1, uses multiprocessing when evaluating at an iteration - **kwargs: arguments passed to _cost_batch_size + dataset_train (QSPRDataset): dataset used to train evaluation models + dataset_eval (QSPRDataset): dataset used for evaluation + n_processes (int, optional): if > 1, uses multiprocessing when evaluating at an iteration + **kwargs: additional arguments Returns: - dict: {'batch_size': tuned batch size} + dict: {'batch_size': int} """ + kwargs['train_ds'] = dataset_train + kwargs['eval_ds'] = dataset_eval abc = ABC(n_bees, _cost_batch_size, num_processes=n_processes, obj_fn_args=kwargs) abc.add_param(1, len(kwargs.get('train_ds').desc_vals), name='batch_size') abc.initialize() @@ -144,20 +180,42 @@ def _cost_arch(vals, **kwargs): return _evaluate_model(trial_spec) -def tune_model_architecture(n_bees: int, n_iter: int, n_processes: int = 1, **kwargs) -> dict: +def tune_model_architecture(n_bees: int, n_iter: int, dataset_train: QSPRDataset, + dataset_eval: QSPRDataset, n_processes: int = 1, + **kwargs) -> dict: """ - Tunes the NN's architecture + Tunes model architecture parameters (number of hidden layers, neurons per hidden layer, neuron + dropout); additional **kwargs can include any in: + [ + # ECNet parameters + 'epochs' (default 100), + 'batch_size' (default 32), + 'valid_size' (default 0.2), + 'patience' (default 32), + 'lr_decay' (default 0.0), + # Adam optim. alg. arguments + 'lr' (default 0.001), + 'beta_1' (default 0.9), + 'beta_2' (default 0.999), + 'eps' (default 1e-8), + 'weight_decay' (default 0.0), + 'amsgrad' (default False) + ] Args: n_bees (int): number of employer bees to use in ABC algorithm n_iter (int): number of iterations, or "search cycles", for ABC algorithm - n_processes (int): if > 1, uses multiprocessing when evaluating at an iteration - **kwargs: arguments passed to _cost_batch_size + dataset_train (QSPRDataset): dataset used to train evaluation models + dataset_eval (QSPRDataset): dataset used for evaluation + n_processes (int, optional): if > 1, uses multiprocessing when evaluating at an iteration + **kwargs: additional arguments Returns: - dict: {'batch_size': opt_val, 'n_hidden': opt_val, 'dropout': opt_val} + dict: {'hidden_dim': int, 'n_hidden': int, 'dropout': float} """ + kwargs['train_ds'] = dataset_train + kwargs['eval_ds'] = dataset_eval abc = ABC(n_bees, _cost_arch, num_processes=n_processes, obj_fn_args=kwargs) abc.add_param(CONFIG['architecture_params_range']['hidden_dim'][0], CONFIG['architecture_params_range']['hidden_dim'][1], name='hidden_dim') @@ -195,20 +253,42 @@ def _cost_train_hp(vals, **kwargs): return _evaluate_model(trial_spec) -def tune_training_parameters(n_bees: int, n_iter: int, n_processes: int = 1, **kwargs) -> dict: +def tune_training_parameters(n_bees: int, n_iter: int, dataset_train: QSPRDataset, + dataset_eval: QSPRDataset, n_processes: int = 1, + **kwargs) -> dict: """ - Tunes the NN's training parameters (Adam optim. fn.) + Tunes learning rate, learning rate decay; additional **kwargs can include any in: + [ + # ECNet parameters + 'epochs' (default 100), + 'batch_size' (default 32), + 'valid_size' (default 0.2), + 'patience' (default 32), + 'hidden_dim' (default 128), + 'n_hidden' (default 2), + 'dropout': (default 0.0), + # Adam optim. alg. arguments + 'beta_1' (default 0.9), + 'beta_2' (default 0.999), + 'eps' (default 1e-8), + 'weight_decay' (default 0.0), + 'amsgrad' (default False) + ] Args: n_bees (int): number of employer bees to use in ABC algorithm n_iter (int): number of iterations, or "search cycles", for ABC algorithm - n_processes (int): if > 1, uses multiprocessing when evaluating at an iteration - **kwargs: arguments passed to _cost_batch_size + dataset_train (QSPRDataset): dataset used to train evaluation models + dataset_eval (QSPRDataset): dataset used for evaluation + n_processes (int, optional): if > 1, uses multiprocessing when evaluating at an iteration + **kwargs: additional arguments Returns: - dict: {'lr': opt_val, 'lr_decay': opt_val} + dict: {'lr': float, 'lr_decay': float} """ + kwargs['train_ds'] = dataset_train + kwargs['eval_ds'] = dataset_eval abc = ABC(n_bees, _cost_train_hp, num_processes=n_processes, obj_fn_args=kwargs) abc.add_param(CONFIG['training_params_range']['lr'][0], CONFIG['training_params_range']['lr'][1], name='lr') diff --git a/examples/getting_started.ipynb b/examples/getting_started.ipynb new file mode 100644 index 0000000..866fb07 --- /dev/null +++ b/examples/getting_started.ipynb @@ -0,0 +1,372 @@ +{ + "metadata": { + "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.8.10" + }, + "orig_nbformat": 4, + "kernelspec": { + "name": "python3", + "display_name": "Python 3.8.10 64-bit ('ecnet': conda)" + }, + "interpreter": { + "hash": "b8ddbdeb4e8d258564393fa38a886a93a7bbb414136361bc7c3a5a1c29ceff9e" + } + }, + "nbformat": 4, + "nbformat_minor": 2, + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Number of samples: 43\nNumber of QSPR descriptors per sample: 1875\n" + ] + } + ], + "source": [ + "# First, let's load our experimental cloud point data; we're using PaDEL-Descriptor to generate QSPR descriptors\n", + "\n", + "from ecnet.datasets import load_cp\n", + "\n", + "dataset = load_cp(as_dataset=True, backend='padel')\n", + "\n", + "print(f'Number of samples: {dataset.desc_vals.shape[0]}')\n", + "print(f'Number of QSPR descriptors per sample: {dataset.desc_vals.shape[1]}')" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Number of samples in the training set: 34\nNumber of samples in the testing set: 9\n" + ] + } + ], + "source": [ + "# Now we create training and testing data subsets; our ANNs regress directly on the training data, and the test set is used to measure blind prediction accuracy\n", + "\n", + "from sklearn.model_selection import train_test_split\n", + "from copy import deepcopy\n", + "\n", + "index_train, index_test = train_test_split([i for i in range(len(dataset))], test_size=0.2, random_state=24)\n", + "\n", + "dataset_train = deepcopy(dataset)\n", + "dataset_train.set_index(index_train)\n", + "\n", + "dataset_test = deepcopy(dataset)\n", + "dataset_test.set_index(index_test)\n", + "\n", + "print(f'Number of samples in the training set: {len(dataset_train)}')\n", + "print(f'Number of samples in the testing set: {len(dataset_test)}')" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
" + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\n\n\n \n \n \n \n 2021-06-30T12:35:48.301674\n image/svg+xml\n \n \n Matplotlib v3.4.2, https://matplotlib.org/\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 \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 \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 \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 \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 \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 \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 \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 \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "# Many QSPR descriptors are not important when predicting cloud point for a database of hydrocarbons and oxygenated compounds; for example, the descriptor counting the number of nitrogen atoms will be zero for all compounds. We will select the descriptors with the highest correlation to cloud point for use as ANN inputs, such that 95% of total correlation (derived from random forest regression) is retained:\n", + "\n", + "from ecnet.tasks.feature_selection import select_rfr\n", + "from matplotlib import pyplot as plt\n", + "\n", + "# Note: we select based on the training set, we want the test set to be 100% blind\n", + "desc_idx, desc_imp = select_rfr(dataset_train, total_importance=0.95, n_estimators=50)\n", + "\n", + "dataset_train.set_desc_index(desc_idx)\n", + "dataset_test.set_desc_index(desc_idx)\n", + "\n", + "# Let's graph importance (individual and cumulative sum) for the selected descriptors:\n", + "rank = [i for i in range(len(desc_imp))]\n", + "tot_imp = [0.0]\n", + "for imp in desc_imp:\n", + " tot_imp.append(tot_imp[-1] + imp)\n", + "tot_imp = tot_imp[1:]\n", + "\n", + "plt.clf()\n", + "fig, ax = plt.subplots(constrained_layout=True)\n", + "ax.set_xlabel('Selected descriptor (most-to-least important)')\n", + "ax.set_ylabel('Descriptor importance')\n", + "ax.plot(rank, desc_imp, color='red')\n", + "ax2 = ax.twinx()\n", + "ax2.set_ylabel('Cumulative importance')\n", + "ax2.plot(rank, tot_imp, color='blue')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\n\n\n \n \n \n \n 2021-06-30T12:35:48.486805\n image/svg+xml\n \n \n Matplotlib v3.4.2, https://matplotlib.org/\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 \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 \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 \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 \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 \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 \n \n \n \n \n \n \n \n\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "# We observe that there are only a handful of QSPR descriptors with significant correlation to cloud point; let's visualize the relationship between kinematic viscosity and the descriptor with the highest importance:\n", + "\n", + "ysi = [dataset_train.target_vals[i][0] for i in range(len(dataset_train))]\n", + "top_desc = [dataset_train.desc_vals[i][0] for i in range(len(dataset_train))]\n", + "\n", + "plt.clf()\n", + "plt.xlabel(f'{dataset_train.desc_names[0]} value')\n", + "plt.ylabel('Experimental cloud point value (deg. C)')\n", + "plt.scatter(top_desc, ysi, color='blue')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Epoch: 0 | Train loss: 3019.848388671875 | Valid loss: 9223372036854775807\n", + "Epoch: 10 | Train loss: 301.50048828125 | Valid loss: 571.7460327148438\n", + "Epoch: 20 | Train loss: 351.8019104003906 | Valid loss: 800.0086669921875\n", + "Epoch: 30 | Train loss: 330.5296325683594 | Valid loss: 539.5159301757812\n", + "Epoch: 40 | Train loss: 264.02142333984375 | Valid loss: 315.75274658203125\n", + "Epoch: 50 | Train loss: 198.6739501953125 | Valid loss: 249.75222778320312\n", + "Epoch: 60 | Train loss: 87.38817596435547 | Valid loss: 125.52989196777344\n", + "Epoch: 70 | Train loss: 59.61891555786133 | Valid loss: 100.54280090332031\n", + "Epoch: 80 | Train loss: 43.34950256347656 | Valid loss: 78.16502380371094\n", + "Epoch: 90 | Train loss: 60.24040985107422 | Valid loss: 91.14484405517578\n" + ] + } + ], + "source": [ + "# Enough exploration, let's train an ANN to predict kinematic viscosity:\n", + "\n", + "from ecnet import ECNet\n", + "\n", + "# Create an ANN with `n` input neurons (where `n` == number of selected QSPR descriptors), 2 hidden layers with 256 neurons each, and one output neuron (corresponding to yield sooting index)\n", + "model = ECNet(dataset_train.desc_vals.shape[1], 1, 256, 2)\n", + "# arguments follow [input dim, output dim, hidden dim, n hidden]\n", + "\n", + "# Train the ANN using training dataset, with a random 20% of the dataset used for validation every epoch:\n", + "train_loss, valid_loss = model.fit(\n", + " dataset=dataset_train, valid_size=0.2, verbose=10,\n", + " patience=32, epochs=300, random_state=None, shuffle=True,\n", + " lr=0.005\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\n\n\n \n \n \n \n 2021-06-30T12:35:48.955909\n image/svg+xml\n \n \n Matplotlib v3.4.2, https://matplotlib.org/\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 \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 \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 \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 \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 \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n", + "image/png": "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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "# We can visualize the training set's loss over training, as well as the validation subset's loss:\n", + "\n", + "from math import sqrt\n", + "\n", + "train_loss = [sqrt(l) for l in train_loss][5:]\n", + "valid_loss = [sqrt(l) for l in valid_loss][5:]\n", + "epoch = [i for i in range(len(train_loss))]\n", + "plt.clf()\n", + "plt.xlabel('Epochs')\n", + "plt.ylabel('Sqrt(Loss)')\n", + "plt.plot(epoch, train_loss, color='blue', label='Training Loss')\n", + "plt.plot(epoch, valid_loss, color='red', label='Validation Loss')\n", + "plt.legend(loc='upper right')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Training median absolute error: 4.776594161987305\nTraining r-squared coefficient: 0.8675852185693186\nTesting median absolute error: 9.086380004882812\nTesting r-squared coefficient: 0.8877325994065388\n" + ] + } + ], + "source": [ + "# Let's calculate median absolute error and r-squared coefficient for each dataset:\n", + "\n", + "from sklearn.metrics import median_absolute_error, r2_score\n", + "\n", + "y_hat_train = model(dataset_train.desc_vals).detach().numpy()\n", + "y_train = dataset_train.target_vals\n", + "train_mae = median_absolute_error(y_hat_train, y_train)\n", + "train_r2 = r2_score(y_hat_train, y_train)\n", + "y_hat_test = model(dataset_test.desc_vals).detach().numpy()\n", + "y_test = dataset_test.target_vals\n", + "test_mae = median_absolute_error(y_hat_test, y_test)\n", + "test_r2 = r2_score(y_hat_test, y_test)\n", + "print(f'Training median absolute error: {train_mae}')\n", + "print(f'Training r-squared coefficient: {train_r2}')\n", + "print(f'Testing median absolute error: {test_mae}')\n", + "print(f'Testing r-squared coefficient: {test_r2}')" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\n\n\n \n \n \n \n 2021-06-30T12:35:49.142649\n image/svg+xml\n \n \n Matplotlib v3.4.2, https://matplotlib.org/\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 \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 \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 \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 \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 \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 \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 \n\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEICAYAAACwDehOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAtlElEQVR4nO3de5xVdb3/8debiyCXvCAaR2IGyzAUHATxegzvlZimZXomoyzR6qRZ/rwc6qd2Iq1MyzpqqCUd55TmT3+oeSohzbv+wBsKx1QcEEMcURG8cZnP74+1ZhiG2Xv2zL7O7Pfz8ZjH3uu799rrM4thffb6XhURmJmZAfQpdwBmZlY5nBTMzKyVk4KZmbVyUjAzs1ZOCmZm1spJwczMWhUtKUj6taRXJT3dpmx7SXdJei593C4tl6QrJD0v6SlJexUrLjMzy0zFGqcg6SBgLfDbiNgjLfsx8HpEXCLpPGC7iDhX0qeAbwKfAvYBfh4R+3R2jB122CFqa2uLEr+ZWW+1YMGC1yJieEev9SvWQSPiXkm17YqPAaakz2cD9wDnpuW/jSRDPSxpW0kjImJFtmPU1tYyf/78gsZtZtbbSVqa6bVStyns1OZC/wqwU/p8Z+ClNu9bnpaZmVkJla2hOb0r6HLdlaTpkuZLmt/U1FSEyMzMqlepk8JKSSMA0sdX0/KXgQ+1ed/ItGwLETErIiZFxKThwzusEjMzs24qWptCBrcB04BL0sc5bcr/VdLvSRqaV3fWnpDJ+vXrWb58Oe+9914h4rUcDRw4kJEjR9K/f/9yh2JmeShaUpD0O5JG5R0kLQcuIEkGN0n6CrAUOCF9+50kPY+eB94Bvtzd4y5fvpyhQ4dSW1uLpDx+A8tVRLBq1SqWL1/O6NGjyx2OmeWhaNVHEXFSRIyIiP4RMTIirouIVRFxaETsGhGHRcTr6XsjIr4RER+OiHER0e0uRe+99x7Dhg1zQighSQwbNsx3Z1axGhqgthb69EkeGxrKHVHlKnX1UUk4IZSez7lVqoYGmD4d3nkn2V66NNkGqK8vX1yVytNcFNiqVauoq6ujrq6OD37wg+y8886t2+vWrcu67/z58znjjDM6Pcb+++9fkFjfeecd6uvrGTduHHvssQcHHngga9euzbrPD3/4w4Ic26xUZszYlBBavPNOUm5bKtqI5lKYNGlStB+8tnjxYj72sY+VKaLNXXjhhQwZMoSzzz67tWzDhg3061cZN2gXX3wxTU1NXHbZZQA8++yz1NbWMmDAgIz7DBkyJGPiqKRzb9aiTx/o6DInQXNz6eOpBJIWRMSkjl7znUIJfOlLX+L0009nn3324ZxzzuHRRx9lv/32Y8KECey///48++yzANxzzz1MnToVSBLKKaecwpQpU9hll1244oorWj9vyJAhre+fMmUKn/3sZ9ltt92or6+nJcnfeeed7LbbbkycOJEzzjij9XPbWrFiBTvvvGmM4JgxY1oTwg033MDkyZOpq6vjtNNOY+PGjZx33nm8++671NXVUe/7bushRo3qWnmlK3r7SET02J+JEydGe4sWLdqiLJsbboioqYmQkscbbujS7lldcMEF8ZOf/CSmTZsWRx11VGzYsCEiIlavXh3r16+PiIi77rorjjvuuIiIuPvuu+Ooo45q3Xe//faL9957L5qammL77bePdevWRUTE4MGDW9//gQ98IF566aXYuHFj7LvvvnHffffFu+++GyNHjowlS5ZERMSJJ57Y+rltPf744zF8+PDYd999Y8aMGfH3v/89IpJzOHXq1Nbjfe1rX4vZs2dvduyOdPXcm5XCDTdEDBoUkdwvJD+DBhX2/3qpFOp3AeZHhutqZdRjlEkpG6A+97nP0bdvXwBWr17NtGnTeO6555DE+vXrO9znqKOOYsCAAQwYMIAdd9yRlStXMnLkyM3eM3ny5Nayuro6GhsbGTJkCLvssktr99CTTjqJWbNmbfH5dXV1LFmyhL/85S/MnTuXvffem4ceeoh58+axYMEC9t57bwDeffdddtxxx4KdC7NSavm/PGMGLFuW3CHMnNkzG5mztY8U6vep6qRQihPcYvDgwa3Pv/e973HwwQdz66230tjYyJQpUzrcp23dft++fdmwYUO33pPNkCFDOO644zjuuOPo06cPd955J1tttRXTpk3j4osv7tJnmVWq+vqemQTaW7asa+XdUdVtCqU4wR1ZvXp1a13+9ddfX/DPHzNmDEuWLKGxsRGAG2+8scP3PfDAA7zxxhsArFu3jkWLFlFTU8Ohhx7KzTffzKuvJrOQvP766yxdmkyq2L9//4x3NmZVq0QDIUrRPlLVSaFcDVDnnHMO559/PhMmTOjyN/tcbL311lx55ZV84hOfYOLEiQwdOpRtttlmi/e98MIL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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "# Now we can visually compare predicted values to experimental values:\n", + "\n", + "plt.clf()\n", + "plt.xlabel('Experimental CP Value (deg. C)')\n", + "plt.ylabel('Predicted CP Value (deg. C)')\n", + "plt.scatter(y_train, y_hat_train, color='blue', label='Training Set')\n", + "plt.scatter(y_test, y_hat_test, color='red', label='Testing Set')\n", + "plt.legend(loc='upper left')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Let's save our model for later use:\n", + "\n", + "model.save('cp_model.pt')" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Training median absolute error: 4.776594161987305\nTraining r-squared coefficient: 0.8675852185693186\nTesting median absolute error: 9.086380004882812\nTesting r-squared coefficient: 0.8877325994065388\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": "
", + "image/svg+xml": "\n\n\n \n \n \n \n 2021-06-30T12:35:49.338191\n image/svg+xml\n \n \n Matplotlib v3.4.2, https://matplotlib.org/\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 \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 \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 \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 \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 \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 \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 \n\n", + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAYUAAAEICAYAAACwDehOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAtlElEQVR4nO3de5xVdb3/8debiyCXvCAaR2IGyzAUHATxegzvlZimZXomoyzR6qRZ/rwc6qd2Iq1MyzpqqCUd55TmT3+oeSohzbv+wBsKx1QcEEMcURG8cZnP74+1ZhiG2Xv2zL7O7Pfz8ZjH3uu799rrM4thffb6XhURmJmZAfQpdwBmZlY5nBTMzKyVk4KZmbVyUjAzs1ZOCmZm1spJwczMWhUtKUj6taRXJT3dpmx7SXdJei593C4tl6QrJD0v6SlJexUrLjMzy0zFGqcg6SBgLfDbiNgjLfsx8HpEXCLpPGC7iDhX0qeAbwKfAvYBfh4R+3R2jB122CFqa2uLEr+ZWW+1YMGC1yJieEev9SvWQSPiXkm17YqPAaakz2cD9wDnpuW/jSRDPSxpW0kjImJFtmPU1tYyf/78gsZtZtbbSVqa6bVStyns1OZC/wqwU/p8Z+ClNu9bnpaZmVkJla2hOb0r6HLdlaTpkuZLmt/U1FSEyMzMqlepk8JKSSMA0sdX0/KXgQ+1ed/ItGwLETErIiZFxKThwzusEjMzs24qWptCBrcB04BL0sc5bcr/VdLvSRqaV3fWnpDJ+vXrWb58Oe+9914h4rUcDRw4kJEjR9K/f/9yh2JmeShaUpD0O5JG5R0kLQcuIEkGN0n6CrAUOCF9+50kPY+eB94Bvtzd4y5fvpyhQ4dSW1uLpDx+A8tVRLBq1SqWL1/O6NGjyx2OmeWhaNVHEXFSRIyIiP4RMTIirouIVRFxaETsGhGHRcTr6XsjIr4RER+OiHER0e0uRe+99x7Dhg1zQighSQwbNsx3Z1axGhqgthb69EkeGxrKHVHlKnX1UUk4IZSez7lVqoYGmD4d3nkn2V66NNkGqK8vX1yVytNcFNiqVauoq6ujrq6OD37wg+y8886t2+vWrcu67/z58znjjDM6Pcb+++9fkFjfeecd6uvrGTduHHvssQcHHngga9euzbrPD3/4w4Ic26xUZszYlBBavPNOUm5bKtqI5lKYNGlStB+8tnjxYj72sY+VKaLNXXjhhQwZMoSzzz67tWzDhg3061cZN2gXX3wxTU1NXHbZZQA8++yz1NbWMmDAgIz7DBkyJGPiqKRzb9aiTx/o6DInQXNz6eOpBJIWRMSkjl7znUIJfOlLX+L0009nn3324ZxzzuHRRx9lv/32Y8KECey///48++yzANxzzz1MnToVSBLKKaecwpQpU9hll1244oorWj9vyJAhre+fMmUKn/3sZ9ltt92or6+nJcnfeeed7LbbbkycOJEzzjij9XPbWrFiBTvvvGmM4JgxY1oTwg033MDkyZOpq6vjtNNOY+PGjZx33nm8++671NXVUe/7bushRo3qWnmlK3r7SET02J+JEydGe4sWLdqiLJsbboioqYmQkscbbujS7lldcMEF8ZOf/CSmTZsWRx11VGzYsCEiIlavXh3r16+PiIi77rorjjvuuIiIuPvuu+Ooo45q3Xe//faL9957L5qammL77bePdevWRUTE4MGDW9//gQ98IF566aXYuHFj7LvvvnHffffFu+++GyNHjowlS5ZERMSJJ57Y+rltPf744zF8+PDYd999Y8aMGfH3v/89IpJzOHXq1Nbjfe1rX4vZs2dvduyOdPXcm5XCDTdEDBoUkdwvJD+DBhX2/3qpFOp3AeZHhutqZdRjlEkpG6A+97nP0bdvXwBWr17NtGnTeO6555DE+vXrO9znqKOOYsCAAQwYMIAdd9yRlStXMnLkyM3eM3ny5Nayuro6GhsbGTJkCLvssktr99CTTjqJWbNmbfH5dXV1LFmyhL/85S/MnTuXvffem4ceeoh58+axYMEC9t57bwDeffdddtxxx4KdC7NSavm/PGMGLFuW3CHMnNkzG5mztY8U6vep6qRQihPcYvDgwa3Pv/e973HwwQdz66230tjYyJQpUzrcp23dft++fdmwYUO33pPNkCFDOO644zjuuOPo06cPd955J1tttRXTpk3j4osv7tJnmVWq+vqemQTaW7asa+XdUdVtCqU4wR1ZvXp1a13+9ddfX/DPHzNmDEuWLKGxsRGAG2+8scP3PfDAA7zxxhsArFu3jkWLFlFTU8Ohhx7KzTffzKuvJrOQvP766yxdmkyq2L9//4x3NmZVq0QDIUrRPlLVSaFcDVDnnHMO559/PhMmTOjyN/tcbL311lx55ZV84hOfYOLEiQwdOpRtttlmi/e98MIL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\n" + }, + "metadata": { + "needs_background": "light" + } + } + ], + "source": [ + "# And test to make sure we can recall it:\n", + "\n", + "from ecnet.model import load_model\n", + "\n", + "model_2 = load_model('cp_model.pt')\n", + "\n", + "y_hat_train = model_2(dataset_train.desc_vals).detach().numpy()\n", + "y_train = dataset_train.target_vals\n", + "train_mae = median_absolute_error(y_hat_train, y_train)\n", + "train_r2 = r2_score(y_hat_train, y_train)\n", + "y_hat_test = model_2(dataset_test.desc_vals).detach().numpy()\n", + "y_test = dataset_test.target_vals\n", + "test_mae = median_absolute_error(y_hat_test, y_test)\n", + "test_r2 = r2_score(y_hat_test, y_test)\n", + "print(f'Training median absolute error: {train_mae}')\n", + "print(f'Training r-squared coefficient: {train_r2}')\n", + "print(f'Testing median absolute error: {test_mae}')\n", + "print(f'Testing r-squared coefficient: {test_r2}')\n", + "\n", + "plt.clf()\n", + "plt.xlabel('Experimental CP Value (deg. C)')\n", + "plt.ylabel('Predicted CP Value (deg. C)')\n", + "plt.scatter(y_train, y_hat_train, color='blue', label='Training Set')\n", + "plt.scatter(y_test, y_hat_test, color='red', label='Testing Set')\n", + "plt.legend(loc='upper left')\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ] +} \ No newline at end of file diff --git a/setup.py b/setup.py index df8a239..f91321c 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ setup( name='ecnet', - version='4.0.0', + version='4.1.0', description='Fuel property prediction using QSPR descriptors', url='https://github.com/ecrl/ecnet', author='Travis Kessler', diff --git a/tests/test_all.py b/tests/test_all.py index d138d0a..99d18cb 100644 --- a/tests/test_all.py +++ b/tests/test_all.py @@ -257,7 +257,7 @@ def test_tune_batch_size(self): targets = [[5.0]] ds_eval = QSPRDataset(smiles, targets, backend=_BACKEND) model = ECNet(_N_DESC, 1, 5, 1) - res = tune_batch_size(1, 1, _N_PROCESSES, model=model, train_ds=ds_train, eval_ds=ds_eval) + res = tune_batch_size(1, 1, ds_train, ds_eval, _N_PROCESSES) self.assertTrue(1 <= res['batch_size'] <= len(ds_train.target_vals)) def test_tune_model_architecture(self): @@ -270,8 +270,7 @@ def test_tune_model_architecture(self): targets = [[5.0]] ds_eval = QSPRDataset(smiles, targets, backend=_BACKEND) model = ECNet(_N_DESC, 1, 5, 1) - res = tune_model_architecture(1, 1, _N_PROCESSES, model=model, train_ds=ds_train, - eval_ds=ds_eval) + res = tune_model_architecture(1, 1, ds_train, ds_eval, _N_PROCESSES) for k in list(res.keys()): self.assertTrue(res[k] >= CONFIG['architecture_params_range'][k][0]) self.assertTrue(res[k] <= CONFIG['architecture_params_range'][k][1]) @@ -285,12 +284,8 @@ def test_tune_training_hps(self): smiles = ['CCCCC'] targets = [[5.0]] ds_eval = QSPRDataset(smiles, targets, backend=_BACKEND) - model = ECNet(_N_DESC, 1, 5, 1) - res = tune_training_parameters(1, 1, _N_PROCESSES, model=model, train_ds=ds_train, - eval_ds=ds_eval) + res = tune_training_parameters(1, 1, ds_train, ds_eval, _N_PROCESSES) for k in list(res.keys()): - if k == 'betas': - continue self.assertTrue(res[k] >= CONFIG['training_params_range'][k][0]) self.assertTrue(res[k] <= CONFIG['training_params_range'][k][1])