Source code for ctlearn_optimizer.bayesian_tpe

import numpy as np
from hyperopt import hp
from hyperopt.pyll.base import scope


[docs]def hyperopt_space(hyper_to_opt): """Create space of hyperparameters for the tree parzen estimators optimizer. This function creates the space of hyperparameter following hyperopt syntax. Parameters: hyper_to_opt (dict): dictionary containing the configuration of the hyperparameters to optimize. This dictionary must follow the next syntax: .. code:: python hyper_to_opt = {'hyperparam_1': {'type': ..., 'range: ..., 'step': ...}, 'hyperparam_2': {'type': ..., 'range: ..., 'step': ...}, ... } See the oficial documentation for more details. Returns: dict: space of hyperparameters following the syntax required by the tree parzen estimators optimization algorithm. Example:: hyper_top_opt = { 'cnn_rnn_dropout':{ 'type': 'uniform', 'range': [0,1]}, 'optimizer_type': { 'type': 'choice', 'range': ['Adadelta', 'Adam', 'RMSProp', 'SGD']}, 'number_of_layers':{ 'type': 'conditional', 'range': { 'value': 1, 'cond_params':{ 'layer1_kernel':{ 'type': 'quniform', 'range': [2, 10], 'step': 1}, 'base_learning_rate':{ 'type': 'loguniform', 'range': [-5, 0]} }}}} """ def aux_hyperopt(key, typee, rangee, keys_list, step): """Return a single hyperparameter element. This auxiliar function returns a dictionary that defines a space of hyperparameters containing a single hyperparameter following hyperopt syntax. A whole space of hyperparameters can be build by updating it with the output of this function. Parameters: key (string): hyperparameter label. typee (string): hyperparameter type. rangee (list): hyperparameter range. keys_list (list): list containing the hyperparameter labels that have already been added to the space. step (int): hyperparameter step, used for q-types. Returns: element (dict): space of hyperparameters containing a single hyperparameter element. keys_list (list): updated list containing the hyperparameter labels. """ # create auxiliary dict dict_type = {'uniform': hp.uniform, 'quniform': hp.quniform, 'loguniform': hp.loguniform, 'qloguniform': hp.qloguniform, 'normal': hp.normal, 'qnormal': hp.qnormal, 'lognormal': hp.lognormal, 'qlognormal': hp.qlognormal, 'choice': hp.choice, 'conditional': hp.choice} # hyperparameters of different types must be handled in different ways not_log_type_strings = ('uniform', 'quniform', 'normal', 'qnormal') log_type_strings = ('loguniform', 'qloguniform', 'lognormal', 'qlognormal') step_type_strings = ('qloguniform', 'qloguniform', 'quniform', 'qnormal') if typee in not_log_type_strings: if typee not in step_type_strings: element = {key: dict_type[typee](key, rangee[0], rangee[1])} # hyperparameters belonging to step_type_strings have an additional # step parameter and their results need to be converted back into # int type else: element = {key: scope.int(dict_type[typee](key, rangee[0], rangee[1], step))} # the range of hyperparameters belonging to log_type_strings must be # modified elif typee in log_type_strings: if typee not in step_type_strings: element = {key: dict_type[typee](key, np.log(rangee[0]), np.log(rangee[1]))} else: element = {key: scope.int(dict_type[typee](key, np.log(rangee[0]), np.log(rangee[1]), step))} # choice type hyperparameters have different syntax elif typee in 'choice': element = {key: dict_type[typee](key, [item for item in rangee])} # conditional type hyperparameters have different syntax elif typee in 'conditional': stream_list = [] for item in rangee: stream_dict = {} stream_dict.update({key: item['value']}) for key_item, iteem in item['cond_params'].items(): # hyperopt space creator doesn't support repeated labels, # so a ! character is appended to each repeated label while key_item in keys_list: key_item = key_item + '!' keys_list.append(key_item) # generate element by using recursion aux = aux_hyperopt(key_item, iteem['type'], iteem['range'], keys_list, iteem.get('step', 1)) stream_dict.update(aux[0]) keys_list = aux[1] stream_list.append(stream_dict) element = {key: dict_type[typee](key, stream_list)} return element, keys_list space = {} keys_list = [] # loop over the hyperparameters to optimize dictionary and add each # hyperparameter to the space for key, item in hyper_to_opt.items(): # get single hyperparameter aux = aux_hyperopt(key, item['type'], item['range'], keys_list, item.get('step', 1)) # add hyperparameter to the whole hyperparameter space space.update(aux[0]) # update keys_list keys_list = aux[1] return space