Code Monkey home page Code Monkey logo

mango's Introduction

Mango: A parallel hyperparameter tuning library

Mango is a python library to find the optimal hyperparameters for machine learning classifiers. Mango enables parallel optimization over complex search spaces of continuous/discrete/categorical values.

Check out the quick 12 seconds demo of Mango approximating a complex decision boundary of SVM

AirSim Drone Demo Video

Mango has the following salient features:

  • Easily define complex search spaces compatible with the scikit-learn.
  • A novel state-of-the-art gradient-free optimizer for continuous/discrete/categorical values.
  • Modular design to schedule objective function on local, cluster, or cloud infrastructure.
  • Failure detection in the application layer for scalability on commodity hardware.
  • New features are continuously added due to the testing and usage in production settings.

Index

  1. Installation
  2. Getting started
  3. Hyperparameter tuning example
  4. Search space definitions
  5. Scheduler
  6. Optional configurations
  7. Additional features
  8. CASH feature
  9. Platform-aware neural architecture search
  10. Mango introduction slides & Mango production usage slides.
  11. Core Mango research papers to cite and novel applications built over Mango

1. Installation

Using pip:

pip install arm-mango

From source:

$ git clone https://github.com/ARM-software/mango.git
$ cd mango
$ pip3 install .

2. Getting Started

Mango is straightforward to use. Following example minimizes the quadratic function whose input is an integer between -10 and 10.

from mango import scheduler, Tuner

# Search space
param_space = dict(x=range(-10,10))

# Quadratic objective Function
@scheduler.serial
def objective(x):
    return x * x

# Initialize and run Tuner
tuner = Tuner(param_space, objective)
results = tuner.minimize()

print(f'Optimal value of parameters: {results["best_params"]} and objective: {results["best_objective"]}')```
# => Optimal value of parameters: {'x': 0}  and objective: 0

3. Hyperparameter Tuning Example

from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score

from mango import Tuner, scheduler

# search space for KNN classifier's hyperparameters
# n_neighbors can vary between 1 and 50, with different choices of algorithm
param_space = dict(n_neighbors=range(1, 50),
                   algorithm=['auto', 'ball_tree', 'kd_tree', 'brute'])


@scheduler.serial
def objective(**params):
    X, y = datasets.load_breast_cancer(return_X_y=True)
    clf = KNeighborsClassifier(**params)
    score = cross_val_score(clf, X, y, scoring='accuracy').mean()
    return score


tuner = Tuner(param_space, objective)
results = tuner.maximize()
print('best parameters:', results['best_params'])
print('best accuracy:', results['best_objective'])
# => best parameters: {'algorithm': 'ball_tree', 'n_neighbors': 11}
# => best accuracy: 0.9332401800962584

Note that best parameters may be different but accuracy should be ~ 0.93. More examples are available in the examples directory (Facebook's Prophet, XGBoost, SVM).

4. Search Space

The search space defines the range and distribution of input parameters to the objective function. Mango search space is compatible with scikit-learn's parameter space definitions used in RandomizedSearchCV or GridSearchCV. The search space is defined as a dictionary with keys being the parameter names (string) and values being list of discreet choices, range of integers or the distributions. Example of some common search spaces are:

Integer

Following space defines x as an integer parameters with values in range(-10, 11) (11 is not included):

param_space = dict(x=range(-10, 11)) #=> -10, -9, ..., 10
# you can use steps for sparse ranges
param_space = dict(x=range(0, 101, 10)) #=> 0, 10, 20, ..., 100

Integers are uniformly sampled from the given range and are assumed to be ordered and treated as continuous variables.

Categorical

Discreet categories can be defined as lists. For example:

# string
param_space = dict(color=['red', 'blue', 'green'])
# float
param_space = dict(v=[0.2, 0.1, 0.3])
# mixed
param_space = dict(max_features=['auto', 0.2, 0.3])

Lists are uniformly sampled and are assumed to be unordered. They are one-hot encoded internally.

Distributions

All the distributions supported by scipy.stats are supported. In general, distributions must provide a rvs method for sampling.

Uniform distribution

Using uniform(loc, scale) one obtains the uniform distribution on [loc, loc + scale].

from scipy.stats import uniform

# uniformly distributed between -1 and 1
param_space = dict(a=uniform(-1, 2))

Log uniform distribution

We have added loguniform distribution by extending the scipy.stats.distributions constructs. Using loguniform(loc, scale) one obtains the loguniform distribution on [10loc, 10loc + scale].

from mango.domain.distribution import loguniform

# log uniformly distributed between 10^-3 and 10^-1
param_space = dict(learning_rate=loguniform(-3, 2))

Hyperparameter search space examples

Example hyperparameter search space for Random Forest Classifier:

param_space =  dict(
    max_features=['sqrt', 'log2', .1, .3, .5, .7, .9],
    n_estimators=range(10, 1000, 50), # 10 to 1000 in steps of 50
    bootstrap=[True, False],
    max_depth=range(1, 20),
    min_samples_leaf=range(1, 10)
)

Example search space for XGBoost Classifier:

from scipy.stats import uniform
from mango.domain.distribution import loguniform

param_space = {
    'n_estimators': range(10, 2001, 100), # 10 to 2000 in steps of 100
    'max_depth': range(1, 15), # 1 to 14
    'reg_alpha': loguniform(-3, 6),  # 10^-3 to 10^3
    'booster': ['gbtree', 'gblinear'],
    'colsample_bylevel': uniform(0.05, 0.95), # 0.05 to 1.0
    'colsample_bytree': uniform(0.05, 0.95), # 0.05 to 1.0
    'learning_rate': loguniform(-3, 3),  # 0.001 to 1
    'reg_lambda': loguniform(-3, 6),  # 10^-3 to 10^3
    'min_child_weight': loguniform(0, 2), # 1 to 100
    'subsample': uniform(0.1, 0.89) # 0.1 to 0.99
}

Example search space for SVM:

from scipy.stats import uniform
from mango.domain.distribution import loguniform

param_dict = {
    'kernel': ['rbf', 'sigmoid'],
    'gamma': uniform(0.1, 4), # 0.1 to 4.1
    'C': loguniform(-7, 8) # 10^-7 to 10
}

5. Scheduler

Mango is designed to take advantage of distributed computing. The objective function can be scheduled to run locally or on a cluster with parallel evaluations. Mango is designed to allow the use of any distributed computing framework (like Celery or Kubernetes). The scheduler module comes with some pre-defined schedulers.

Serial scheduler

Serial scheduler runs locally with one objective function evaluation at a time

from mango import scheduler

@scheduler.serial
def objective(x):
    return x * x

Parallel scheduler

Parallel scheduler runs locally and uses joblib to evaluate the objective functions in parallel

from mango import scheduler

@scheduler.parallel(n_jobs=2)
def objective(x):
    return x * x

n_jobs specifies the number of parallel evaluations. n_jobs = -1 uses all the available cpu cores on the machine. See simple_parallel for full working example.

Custom distributed scheduler

Users can define their own distribution strategies using custom scheduler. To do so, users need to define an objective function that takes a list of parameters and returns the list of results:

from mango import scheduler

@scheduler.custom(n_jobs=4)
def objective(params_batch):
    """ Template for custom distributed objective function
    Args:
        params_batch (list): Batch of parameter dictionaries to be evaluated in parallel

    Returns:
        list: Values of objective function at given parameters
    """
    # evaluate the objective on a distributed framework
    ...
    return results

For example the following snippet uses Celery:

import celery
from mango import Tuner, scheduler

# connect to celery backend
app = celery.Celery('simple_celery', backend='rpc://')

# remote celery task
@app.task
def remote_objective(x):
    return x * x

@scheduler.custom(n_jobs=4)
def objective(params_batch):
    jobs = celery.group(remote_objective.s(params['x']) for params in params_batch)()
    return jobs.get()

param_space = dict(x=range(-10, 10))

tuner = Tuner(param_space, objective)
results = tuner.minimize()

A working example to tune hyperparameters of KNN using Celery is here.

6. Optional configurations

The default configuration parameters used by the Mango as below:

{'param_dict': ...,
 'userObjective': ...,
 'domain_size': 5000,
 'initial_random': 1,
 'num_iteration': 20,
 'batch_size': 1}

The configuration parameters are:

  • domain_size: The size which is explored in each iteration by the gaussian process. Generally, a larger size is preferred if higher dimensional functions are optimized. More on this will be added with details about the internals of bayesian optimization.

  • initial_random: The number of random samples tried. Note: Mango returns all the random samples together. Users can exploit this to parallelize the random runs without any constraint.

  • num_iteration: The total number of iterations used by Mango to find the optimal value.

  • batch_size: The size of args_list passed to the objective function for parallel evaluation. For larger batch sizes, Mango internally uses intelligent sampling to decide the optimal samples to evaluate.

  • early_stopping: A Callable to specify custom stopping criteria. The callback has the following signature:

    def early_stopping(results):
       '''
           results is the same as dict returned by tuner
           keys available: params_tries, objective_values,
               best_objective, best_params
       '''
       ...
       return True/False

    Early stopping is one of Mango's important features that allow to early terminate the current parallel search based on the custom user-designed criteria, such as the total optimization time spent, current validation accuracy achieved, or improvements in the past few iterations. For usage see early stopping examples notebook.

  • constraint: A callable to specify constraints on parameter space. It has the following signature:

    def constraint(samples: List[dict]) -> List[bool]:
      '''
          Given a list of samples (each sample is a dict with parameter names as keys)
          Returns a list of True/False elements indicating whether the corresponding sample
          satisfies the constraints or not
      '''

    See this notebook for an example.

  • initial_custom: A list of initial evaluation points to warm up the optimizer instead of random sampling. It can be either:

    • A list of dict with parameters. For example, for a search space with two parameters x1 and x2 the input could be: [{'x1': 10, 'x2': -5}, {'x1': 0, 'x2': 10}].
    • A list of tuple with parameters and objective function values. For example, if the objective function is to add x1 and x2 the input could be: [({'x1': 10, 'x2': -5}, 5), ({'x1': 0, 'x2': 10}, 10)].

    This allows the user to customize the initial evaluation points and therefore guide the optimization process. It also enables starting the optimizer from the results of a previous tuner run (see this notebook for a working example). Note that if initial_custom option is given then initial_random is ignored.

The default configuration parameters can be modified, as shown below. Only the parameters whose values need to adjusted can be passed as the dictionary.

conf_dict = dict(num_iteration=40, domain_size=10000, initial_random=3)

tuner = Tuner(param_dict, objective, conf_dict)

7. Additional Features

Handling runtime failed evaluation

At runtime, failed evaluations are widespread in production deployments. Mango abstractions enable users to make progress even in the presence of failures by only using the correct evaluations. The syntax can return the successful evaluation, and the user can flexibly keep track of failures, for example, using timeouts. Examples showing the usage of Mango in the presence of failures: serial execution and parallel execution

Neural Architecture Search

Mango can also do an efficient neural architecture search. An example on the MNIST dataset to search for optimal filter sizes, the number of filters, etc., is available.

More extensive examples are available in the THIN-Bayes folder doing Neural Architecture Search for a class of neural networks and classical models for different regression and classification tasks.

8. Combiner Classifier Selection and Optimization (CASH)

Mango now provides a novel functionality of combined classifier selection and optimization. It allows developers to directly specify a set of classifiers along with their different hyperparameter spaces. Mango internally finds the best classifier along with the optimal parameters with the least possible number of overall iterations. The examples are available here

The important parts in the skeletion code are as below.

from mango import MetaTuner

#define search spaces and objective functions as done for tuner.

param_space_list = [param_space1, param_space2, param_space3, param_space4, ..]
objective_list = [objective_1, objective_2, objective_3, objective_4, ..]

metatuner = MetaTuner(param_space_list, objective_list)

results = metatuner.run()

print('best_objective:',results['best_objective'])
print('best_params:',results['best_params'])
print('best_objective_fid:',results['best_objective_fid'])

Participate

Core Papers to Cite Mango

More technical details are available in the Mango paper-1 (ICASSP 2020) and Mango paper-2 (CogMI 2021) Please cite them as:

@inproceedings{sandha2020mango,
  title={Mango: A Python Library for Parallel Hyperparameter Tuning},
  author={Sandha, Sandeep Singh and Aggarwal, Mohit and Fedorov, Igor and Srivastava, Mani},
  booktitle={ICASSP 2020-2020 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP)},
  pages={3987--3991},
  year={2020},
  organization={IEEE}
}
@inproceedings{sandha2021mango,
  title={Enabling Hyperparameter Tuning of Machine Learning Classifiers in Production},
  author={Sandha, Sandeep Singh and Aggarwal, Mohit and Saha, Swapnil Sayan and Srivastava, Mani},
  booktitle={CogMI 2021, IEEE International Conference on Cognitive Machine Intelligence},
  year={2021},
  organization={IEEE}
}

Novel Applications built over Mango

@article{saha2022auritus,
  title={Auritus: An open-source optimization toolkit for training and development of human movement models and filters using earables},
  author={Saha, Swapnil Sayan and Sandha, Sandeep Singh and Pei, Siyou and Jain, Vivek and Wang, Ziqi and Li, Yuchen and Sarker, Ankur and Srivastava, Mani},
  journal={Proceedings of the ACM on Interactive, Mobile, Wearable and Ubiquitous Technologies},
  volume={6},
  number={2},
  pages={1--34},
  year={2022},
  publisher={ACM New York, NY, USA}
}
@article{saha2022tinyodom,
  title={Tinyodom: Hardware-aware efficient neural inertial navigation},
  author={Saha, Swapnil Sayan and Sandha, Sandeep Singh and Garcia, Luis Antonio and Srivastava, Mani},
  journal={Proceedings of the ACM on Interactive, Mobile, Wearable and Ubiquitous Technologies},
  volume={6},
  number={2},
  pages={1--32},
  year={2022},
  publisher={ACM New York, NY, USA}
}
@article{saha2022thin,
  title={THIN-Bayes: Platform-Aware Machine Learning for Low-End IoT Devices},
  author={Saha, Swapnil Sayan and Sandha, Sandeep Singh and Aggarwal, Mohit and Srivastava, Mani},
  year={2022}
}

Slides

Slides explaining Mango abstractions and design choices are available. Mango Slides-1, Mango Slides-2.

Contribute

Please take a look at open issues if you are looking for areas to contribute to.

Questions

For any questions feel free to reach out by creating an issue here.

mango's People

Contributors

asah avatar dependabot[bot] avatar gbrener avatar sandeep-iitr avatar tihom avatar turkalpmd avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mango's Issues

Negative domain error

I'm trying to find the minimum of x*x+5*x. I'm using the code below:

#mangotest.py

from mango import Tuner, scheduler
from scipy.stats import uniform

# search space
param_space = dict(x=uniform(-10, -1))

@scheduler.parallel(n_jobs=1)
def objective(x):
    return (x * x + 5*x)

tuner = Tuner(param_space, objective)  
results = tuner.minimize()  

However, I'm getting the following error:

Traceback (most recent call last):
  File "mangotest.py", line 16, in <module>
    results = tuner.minimize()  
  File "/usr/local/lib/python3.8/dist-packages/mango/tuner.py", line 153, in minimize
    return self.run()
  File "/usr/local/lib/python3.8/dist-packages/mango/tuner.py", line 140, in run
    self.results = self.runBayesianOptimizer()
  File "/usr/local/lib/python3.8/dist-packages/mango/tuner.py", line 182, in runBayesianOptimizer
    X_list, Y_list, X_tried = self.run_initial()
  File "/usr/local/lib/python3.8/dist-packages/mango/tuner.py", line 162, in run_initial
    X_tried = self.ds.get_random_sample(self.config.initial_random)
  File "/usr/local/lib/python3.8/dist-packages/mango/domain/domain_space.py", line 49, in get_random_sample
    domain_list = list(BatchParameterSampler(self.param_dict, n_iter=size))
  File "/usr/local/lib/python3.8/dist-packages/mango/domain/batch_parameter_sampler.py", line 61, in __iter__
    samples.append(v.rvs(random_state=rng, size=self.n_iter))
  File "/usr/local/lib/python3.8/dist-packages/scipy/stats/_distn_infrastructure.py", line 467, in rvs
    return self.dist.rvs(*self.args, **kwds)
  File "/usr/local/lib/python3.8/dist-packages/scipy/stats/_distn_infrastructure.py", line 1066, in rvs
    raise ValueError(message)
ValueError: Domain error in arguments. The `scale` parameter must be positive for all distributions, and many distributions have restrictions on shape parameters. Please see the `scipy.stats.uniform` documentation for details.


Interestingly, there is no error if I set param_space = dict(x=uniform(-10, 0)) so I'm guessing there is an issue with both limits of the search space being negative. Is this the intended behavior? If so, why? Thank you!

Need to add detailed documentation on Mango

I am creating an issue for reference to prioritize detailed documentation for Mango: The API capabilities in detail, algorithmic novelties, and benchmark comparisons to other libraries.

Tuning in parallel takes more time than serial

When I try to optimize over multiple CPU cores, the tuning takes significantly longer than when optimizing on a single core serially. I am attaching a simple example here where serial runs in 49 seconds and parallel takes 81 seconds.
mango.pdf

Demo video code

Is there any example code that does what was shown in the demo video or is that separate?

'Tuner' object has no attribute 'getConf'

Hello and thanks for this project!

I am trying to run the code in 'readme' and the example i used is 'Hyperparameter Tuning Example' which is provided in the code.

My code is the same as yours:
from sklearn import datasets
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score

from mango import Tuner, scheduler

search space for KNN classifier's hyperparameters

n_neighbors can vary between 1 and 50, with different choices of algorithm

param_space = dict(n_neighbors=range(1, 50),
algorithm=['auto', 'ball_tree', 'kd_tree', 'brute'])

@scheduler.serial
def objective(**params):
X, y = datasets.load_breast_cancer(return_X_y=True)
clf = KNeighborsClassifier(**params)
score = cross_val_score(clf, X, y, scoring='accuracy').mean()
return score

tuner = Tuner(param_space, objective)
results = tuner.maximize()
print('best parameters:', results['best_params'])
print('best accuracy:', results['best_objective'])

=> best parameters: {'algorithm': 'auto', 'n_neighbors': 11}

=> best accuracy: 0.931486122714193

However, i got a better accuracy(best parameters: {'algorithm': 'kd_tree', 'n_neighbors': 13},best accuracy: 0.9332401800962584).
Since you have mentioned that'Note that best parameters may be different but accuracy should be ~ 0.9315.' Therefore i wonder why i could get the better result.
螢幕截圖 2023-01-20 15 32 44

I am looking forwards to the reply. Thank you!

Use inside the class?

Sorry if it is a basic question, but I was curious if there is a way to use an instance method as my objective function?
It seems like the 'self' in the argument list messes things up a bit.

from mango import scheduler, Tuner

class experiment:
    def __init__(self):
        self.param_space = dict(x=range(-10,10))
                     
            
    @scheduler.serial
    def objective(self, x): 
        return x * x
    
                                
    def execute(self):
        tuner = Tuner(self.param_space, self.objective)
        results = tuner.minimize()
        print(f'Optimal value of parameters: {results["best_params"]} and objective: {results["best_objective"]}')

e = experiment()
e.execute()

When I run this I get the following error:


---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-76-9bf0d28ab75c> in <module>
      1 e = experiment()
----> 2 e.execute()

<ipython-input-75-c8a11d823cc8> in execute(self)
     13     def execute(self):
     14         tuner = Tuner(self.param_space, self.objective)
---> 15         results = tuner.minimize()
     16         print(f'Optimal value of parameters: {results["best_params"]} and objective: {results["best_objective"]}')

~/Desktop/Work/scoring/.env/lib/python3.7/site-packages/mango/tuner.py in minimize(self)
    130         return self.run()
    131 
--> 132     def runBayesianOptimizer(self):
    133         results = dict()
    134 

~/Desktop/Work/scoring/.env/lib/python3.7/site-packages/mango/tuner.py in run(self)
    117             self.results = self.runBayesianOptimizer()
    118         elif self.config.is_random:
--> 119             self.results = self.runRandomOptimizer()
    120         else:
    121             raise ValueError("Unknown Optimizer %s" % self.config.optimizer)

~/Desktop/Work/scoring/.env/lib/python3.7/site-packages/mango/tuner.py in runBayesianOptimizer(self)
    140         print(self)
    141         X_list, Y_list = self.runUserObjective(random_hyper_parameters)
--> 142 
    143         # in case initial random results are invalid try different samples
    144         n_tries = 1

~/Desktop/Work/scoring/.env/lib/python3.7/site-packages/mango/tuner.py in runUserObjective(self, X_next_PS)
    289         X_list_evaluated = X_next_PS
    290         results = self.objective_function(X_next_PS)
--> 291         Y_list_evaluated = results
    292 
    293         # if result is a tuple, then there is possibility that partial values are evaluated

TypeError: wrapper() takes 1 positional argument but 2 were given

Any suggestions are appreciated.

Is it possible to add an initial data point?

The way Im currently using mango, I will always have a first run with good defaults. Is it possible to use this information somehow? I have quite wide ranges for my hyper parameters, and I think this would help a lot.

Python int too large to convert to C long

param_dict = {"s": range(50,600),
"Ts": range(20,100),
"Ts2": range(20,100),
"c":range(1,100),
"n_hidden1":range(100,1000),
"n_hidden2":range(10,100),
"n_hidden3":range(5,30),
"selected_range": [0.5,0.6,0.7,0.8,0.9]}

conf_Dict = dict()
conf_Dict['batch_size'] = 1
conf_Dict['num_iteration'] = 100
conf_Dict['domain_size'] = 50000
conf_Dict['initial_random'] = 1

@scheduler.parallel(n_jobs=2)
def objective(s,Ts,Ts2,c,n_hidden1,n_hidden2,n_hidden3,selected_range):

global X, Y, N, p

f1s=[]
accs=[]
all_common_numbers=[]
all_loss=[]

return random.randint(1, 100000)

error:
mango_results = tuner.minimize()

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\tuner.py:160 in minimize
return self.run()

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\tuner.py:147 in run
self.results = self.runBayesianOptimizer()

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\tuner.py:208 in runBayesianOptimizer
X_list, Y_list, X_tried = self.run_initial()

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\tuner.py:184 in run_initial
X_tried = self.ds.get_random_sample(self.config.initial_random)

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\domain\domain_space.py:45 in get_random_sample
return self._get_random_sample(size)

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\domain\domain_space.py:63 in _get_random_sample
domain_list = list(BatchParameterSampler(self.param_dict, n_iter=size))

File ~\AppData\Local\anaconda3\envs\Ecoli\Lib\site-packages\mango\domain\batch_parameter_sampler.py:49 in iter
for i in sample_without_replacement(grid_size, n_iter,

File sklearn\utils_random.pyx:218 in sklearn.utils._random.sample_without_replacement

OverflowError: Python int too large to convert to C long

Voting classifier

Is it possible to use mango with Voting classifier? And tune parameters for each classifier that takes part in the ensamble.

Questions regarding failed evaluations and dynamic updates of the surrogate function

Hey,
I have some questions regarding the documentation, it would be great if you could update it. Additionally I have one feature request, depending on how Mango works at the moment.

First, I'm interested in how exactly Mango handles failed evaluations. Neither the documentation nor the paper are really clear about this. From my tests, I can see that if I have some jobs failing I effectively get more runs than without jobs failing. But it looks like this is only the case for the initial random runs, not for the Bayesian runs. And it seems to only try twice until it gives up, is that true? It would be nice if you could add a bit to the documentation about this.

Second, I wonder if it is possible to use the mechanism of failed evaluations to somehow have a dynamic update of the surrogate function. In my application the evaluations can take quite different runtimes depending on the hyperparameters. Therefore it would be cool if I could update the surrogate function every time I get one new result, this is what I mean with a dynamic update of the surrogate function. Currently I need to wait for the whole batch of hyperparameters to finish its evaluation and only then I can return it.
If possible it would be amazing if you could provide a builtin functionality for this. Otherwise I was wondering if I could use the mechanism of failed evaluations to do this by hand:

  1. Get a batch of hyperparameters. Evaluate them in parallel by submitting a new task for each (on Slurm).
  2. Whenever a single task returns the score, return this to the Mango Optimizer. For the Mango Optimizer, it would look like all but this one evaluations failed.
  3. Mango gets me a new batch of hyperparameters, I again submit the Slurm tasks to calculate them.
  4. While waiting for them to return, one of the tasks of the first batch returns its score. I again return this score to the Mango optimizer which will in turn provide me with a new batch of hyperparameters...

I was hoping this would be possible, but since I am not sure about how Mango handles the failed evaluations I'm not sure it works. I feel like it could be an issue because Mango needs to know that the other jobs didn't fail but that they are still in progress, otherwise it might just try them again. I'm very interested to hear your opinion about this.

Also, thanks for this great package! It's really cool, I like it a lot.
Cheers,
Timo

Dependent parameters

Is it possible to use a param_space dictionary where one parameter depends on another? E.g. hidden layer dimensions on a number of layers in neural networks.

some questions on enabling a specific algorithm & celery workers constant usage optimization

Hello,

First of all, kudos for your lib, it's by far the more convenient in the subject I've tested so far, particularly when one wants to search in // using multiple nodes.

Hallucination / Clustering mode
Having read the mango slides PDF, I've difficulties to match in the Tuner conf dict the hallucination & clustering approaches depicted in Mango Experiments.

Reading the 1D_Mango_Different_Parallelization.ipynb or other notebooks did not clarify that for me.

Is it just a matter of batch > 1 to enable what you call the "hallucination" mode? What about the clustering mode?
I think the README.md could be improved in this area. Are those algorithms compatible to celery workers usage?

Celery workers constant usage
So far, I've seen that my celery workers aren't used constantly, which makes sense since some experiment results might guide next experiments.

I used the simple_celery.py example approach, tried different values for n_jobs of the @scheduler.custom decorator, as well as several batch_size and num_iteration but none of these approaches avoid the lack of use of some workers for a long time.
Is there any tuning recommendations to optimize the celery worker usage?

Each task takes around 30 to 60 seconds to complete, as I'm not searching for hyper-parameters, but instead using mango to search for parameters needed for features engineering, and features generation takes time with my use-case.
Can this long celery task duration be part of my issue?

BTW, why not using the @scheduler.celery decorator in your celery examples?

Thanks, and keep the good work!

early stopping ?

Have you considered support for stopping Mango early if the objective function doesn't improve enough?

Would you be open to a contribution PR?

thanks!

ARIMA example: Error displaying widget: model not found

Thank you so much for this package. I am some trouble implementing it though.

I followed the ARIMA model example. Everything was fine until "results = tuner.minimize()" where I received
"Error displaying widget: model not found"

By the way, I am new to ARIMA model, what's the recommended range for param_space and num_iteration?
image

Question about the definition of num_iteration

Hi,

I set the num_iteration=25 and initial_random=10, and n_jobs=4. However, the time cost is longer using @scheduler.parallel than using @scheduler.serial. I wonder why using parallel Bayesian optimization is slower? I supposed that the numbers of the total samples they generate are same which is (25+10=35) ? Please correct me if I misunderstand. Thank you!

Question about Serial scheduler and parallel scheduler

Thank you for the amazing work! I have questions about the definition.

  1. I wonder if @serial scheduler is to execute the original Bayesian optimization algorithm without parallelization?
  2. Could I assume that if I don't specify the scheduler, Serial scheduler is used by default?
  3. To perform Bayesian optimization in parallel, what are the definition of n_jobs and batch_size for? What happens if the numbers are different? ex. n_jobs=m and batch_size=n. Does it run m runs or n runs simultaneously?

Thank you very much!

clustering mode scikit-learn>=0.23.0 bug

Hello,

Clustering mode seems to require scikit-learn<0.23.0, at least with my search space.
Otherwise, I get the following error after the first iteration:

/.virtualenvs/lib/python3.8/site-packages/mango/tuner.py in maximize(self)
    126
    127     def maximize(self):
--> 128         return self.run()
    129
    130     def minimize(self):

~/.virtualenvs/lib/python3.8/site-packages/mango/tuner.py in run(self)
    117     def run(self):
    118         if self.config.is_bayesian:
--> 119             self.results = self.runBayesianOptimizer()
    120         elif self.config.is_random:
    121             self.results = self.runRandomOptimizer()

~/.virtualenvs/lib/python3.8/site-packages/mango/tuner.py in runBayesianOptimizer(self)
    194                                                     batch_size=self.config.batch_size)
    195             elif self.config.strategy_is_clustering:
--> 196                 X_next_batch = Optimizer.get_next_batch_clustering(X_sample,Y_scaled, X_domain_np,
    197                                                                    batch_size=self.config.batch_size)
    198             else:

~/.virtualenvs/lib/python3.8/site-packages/mango/optimizer/bayesian_learning.py in get_next_batch_clustering(self, X, Y, X_tries, batch_size)
    290
    291             # Do the domain space based clustering on the best points
--> 292             kmeans = KMeans(n_clusters=batch_size, random_state=0).fit(x_best_acq_domain)
    293             cluster_pred_domain = kmeans.labels_.reshape(kmeans.labels_.shape[0])
    294

~/.virtualenvs/lib/python3.8/site-packages/sklearn/cluster/_kmeans.py in fit(self, X, y, sample_weight)
    995         # verify that the number of samples given is larger than k
    996         if _num_samples(X) < self.n_clusters:
--> 997             raise ValueError("n_samples=%d should be >= n_clusters=%d" % (
    998                 _num_samples(X), self.n_clusters))
    999

ValueError: n_samples=2 should be >= n_clusters=4

My conf_dict

conf_dict = {
    "batch_size": 4,
    "num_iteration": 100,
    "parallel_strategy": "clustering",
}

Looking at the scikit-learn changelog, we see lots of KMeans changes during 0.23 cycle:
https://scikit-learn.org/stable/whats_new/v0.23.html#version-0-23-2

I was able to pin point the exact version which introduced the issue: 0.23.0
I think a simple 'scikit_learn>=0.21.3, <0.23.0' in setup.py will do the trick, until you find how to fix it for these KMeans changes.

So the latest scikit-learn version suitable for clustering mode is 0.22.2.post1, which luckily I had on the server I used initially.

BTW the clustering mode does converge faster indeed. Thank you very much!

ValueError when using mango

Hi,

I am trying to use mango for the first time and I was trying to fine tune the hyperparameters of a simple CNN model. I chose to start with those simple hyperparameters:

HYPERPARAMETERS =
{'groups': [64, 32, 16, 8],
 'in_channels': [64],
 'kernel_size': [5, 10, 15, 20],
 'lr': [0.01, 0.1, 0.001],
 'n_classes': [4]}

And I defined the objective function as following:

Import pytorch_lightning as 
From torch.utils.data import DataLoader

def objective(hyperparams):
  trainset = EEGDataset(path, train_idx)#, transform=GraphFilter(filters, idx))
  testset = EEGDataset(path, test_idx)#, transform=GraphFilter(filters, idx))
  clear_output()
  train_loader = DataLoader(trainset, batch_size=32, shuffle=True)
  test_loader = DataLoader(testset, batch_size=32)

  model = BaselineModel(params)
  trainer = pl.Trainer(max_epochs=1)

  trainer.fit(model, train_loader, test_loader)
  value = trainer.callback_metrics['train_loss'].item()
  return [value]

And then started the optimization as following:


from mango import Tuner

print("Running hyperparameter search...")
config = dict()
config["optimizer"] = "Bayesian"
config["num_iteration"] = 5

tuner = Tuner(HYPERPARAMETERS, 
              objective=objective,
              conf_dict=config) 
results = tuner.minimize()

I tried 5 trials to check that everything is working before i start the real optimization. It worked at the begining them it gave me this error

ValueError: Found input variables with inconsistent numbers of samples: [7, 6]

I don’t understand where this error comes from, It would be very nice if you can help me with this issue.

ValueError: XA and XB must have the same number of columns (i.e. feature dimension.)

Hi!

I am running Mango 1.1.0 for a HPS. After a few iterations in, I get the following error logs:

image

My params to search area:

param_dict = {"param1": uniform(0.01, 1),
              "param2": uniform(0.01, 1),
             "param3": uniform(0.01, 1),
             "param4": uniform(0, 1),
             "param5": uniform(0.5, 0.49)}

I am running the default configuration parameters.

Any ideas what might cause this or how to fix?

What to return in case of failure?

My model returns a NaN loss when a configuration cannot be evaluated. This seems to sometimes be allowed, and sometimes cause a crash. What should be the return value in case of a failure?

return None

TypeError: unsupported operand type(s) for *: 'int' and 'NoneType'

return float("NaN")

ValueError: Input contains NaN, infinity or a value too large for dtype('float64').

Many thanks.

How to avoid fails in parallel

First of all thanks for this package. It is super helpful for me and my workflow.

I was just wondering if you have any tips on how to get rid of fails from parallel workflow?

Most of the time I run it I get errors like this:
ValueError: n_samples=64 should be >= n_clusters=100.

or the same just for batches.

Do you have any simple tips to guide me in the right direction to overcome this problem.

Keep up the good work :)

`n_iterations`

@sandeep-iitr there have been few issues about the meaning of n_iterations in parallel mode. Intuitively (since all other tuning libraries have this behavior) n_iterations should be same as number of objective function evaluation but Mango does n_iterations x batch_size.

I propose that we deprecate n_iterations and add a new parameter: n_samples Number of function evaluation would always be == n_samples in serial and parallel cases. In parallel case the number of batches is calculated as n_samples / batch_size.

We would add a deprecation warning to n_iterations parameter to warn users about the change and update all docs and examples to use n_samples. This way it won't break existing usage.

I can make all the changes needed.

batchsize of initial_random runs is unexpected

Hey,
again me, but this is a different issue so I didn't want to merge it with the other one. I noticed that when setting initial_random e.g. to 20 and batch_size to 5, the size of the very first hyperparameter batch is initial_random, not batch_size. You can see this in the following minimal working example:

from mango import Tuner, scheduler
import numpy as np

def objective(hparam_batches): 
    size = len(hparam_batches)
    print('Length:', size)
    # The first time, len(hparam_batches) doesn't equal batch_size but initial_random!
    return hparam_batches, np.random.randn(size)

configs = {
            'initial_random': 20,
            'num_iteration': 10,
            'batch_size': 5
            }
param_space = {'foo': range(100, 200)}
tuner = Tuner(param_space, objective, configs)
results = tuner.minimize()

I understand that this can be useful behaviour since you can parallelize the random runs without any constraint. However, usually if I set a batch_size of 5 this means that I will have asked my Slurm scheduler for an allocation of 5 GPUs to evaluate my networks in parallel, even for the random runs. Therefore this behaviour comes very unexpected to me. It would be nice if you could make this clearer in the documentation.
Additionally, I would expect it's probably quite common that people would wish the batchsize to be always the same. Therefore, maybe it would be worth to offer a flag to turn this behaviour off and on. But maybe this is not true in general.

Cheers,
Timo

Scaling input parameters

Hey there. Today I tried to plot the optimization progress of a mango run using a contour plot but then I ran into an issue. In my data, there's two continuous input parameters with very different scales (see code example below). After fitting the GaussianProcessRegressor the results were pretty much unusable, as can be seen by the plot (provided below). Only after scaling both features to the [0,1] interval, the results were what I expected them to be.

Correct me if I'm wrong, but after looking through the codebase, I couldn't find any scaling applied to continuous variables. I guess my question is, are we supposed to scale our parameters before passing them to Tuner as param_dict? If so, this should probably be mentioned in the docs, as this behavior is not very intuitive. I would also like to make a feature request, to make the scaling part of mango. The limits used for scaling are already known from the distributions defined in param_dict.

Here's some code to test the behavior:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import Matern

# Generate data
data = [[0.519712, 1438.106604, 0.9890267207690076],
 [0.588307, 1220.578838, 0.6265765135227674],
 [0.55075, 906.374136, 0.9308240637759998],
 [0.355543, 1403.904598, 1.001475488132783],
 [0.430634, 840.591423, 1.0267490857885169],
 [0.477513, 1062.385949, 0.4883283241359153],
 [0.571532, 392.193584, 0.8084230446619398],
 [0.310248, 1012.246997, 0.9610352617817592],
 [0.464245, 248.483425, 0.701506256396162],
 [0.526382, 591.378226, 0.8894154056980089],
 [0.434667, 1302.143909, 0.9839202744250197],
 [0.391176, 488.536072, 0.9349843519807586],
 [0.474439, 1071.135636, 0.5342269053336064],
 [0.548409, 231.415683, 0.9947894009673353],
 [0.47567, 718.013638, 0.5847223173442994],
 [0.435327, 1207.326743, 1.0041979428572427]]

df = pd.DataFrame(data,columns=("varA","varB","result"))

# Specify parameter limits
xmin = np.array([0.3,200])
xmax = np.array([0.6,1500])

# Define gp
kernel = Matern(nu=2.5)
gp = GaussianProcessRegressor(
    kernel=kernel,
    n_restarts_optimizer=100,
    random_state=1,
    normalize_y=True,
)

def minmax_scale(X, xmin, xmax):
    return (X - xmin) / (xmax - xmin)

X_train = df.iloc[:,:-1].values
X_train = minmax_scale(X=X_train,xmin = xmin, xmax = xmax) # comment out for comparison
y_train = df.iloc[:,-1].values

gp.fit(X=X_train, y=y_train)


def generate_contour_plot(X_train, gp_model, resolution=100):
    x_min, x_max = X_train[:, 0].min(), X_train[:, 0].max()
    y_min, y_max = X_train[:, 1].min(), X_train[:, 1].max()
    x_range = np.linspace(x_min, x_max, resolution)
    y_range = np.linspace(y_min, y_max, resolution)
    X, Y = np.meshgrid(x_range, y_range)
    xy = np.column_stack([X.ravel(), Y.ravel()])

    Z_mean = gp_model.predict(xy)
    Z_mean = Z_mean.reshape(X.shape)

    fig, ax = plt.subplots(figsize=(10, 6))
    contour = ax.contourf(X, Y, Z_mean, cmap='viridis', alpha=0.8, levels=50)
    fig.colorbar(contour, ax=ax, label='result')
    ax.scatter(X_train[:, 0], X_train[:, 1], c='red', marker='x', label='Training Data')
    ax.set_xlabel("varA")
    ax.set_ylabel("varB")
    ax.set_title('Gaussian Process Contour Plot')
    ax.legend()
    plt.show()

generate_contour_plot(X_train=X_train, gp_model=gp)

The gp response with scaled data:
image

The gp response with raw data:
image

Wrong minimum calculation

I tried the following objective function:

def objective(x):
    return (x-1) * (x-2) +1

and it returned the wrong answer x=1 and objective value = 1.

code:

from mango import scheduler, Tuner
# Search space
param_space = dict(x=range(-10,10))

# Quadratic objective Function
@scheduler.serial
def objective(x):
    return (x-1) * (x-2) +1

# Initialize and run Tuner
tuner = Tuner(param_space, objective)
results = tuner.minimize()

print(f'Optimal value of parameters: {results["best_params"]} and objective: {results["best_objective"]}' )
# => Optimal value of parameters: {'x': 1.5}  and objective: 0.72

Installing issue

Hi,
I would like to install the package on my virtual environment and I get this error:
ERROR: Could not find a version that satisfies the requirement numpy==1.17.0 (from mango==1.0.0) (from versions: 1.11.3, 1.13.3, 1.14.0, 1.14.1, 1.14.2, 1.14.3, 1.14.5, 1.15.0, 1.15.2, 1.15.4, 1.16.0, 1.16.2, 1.16.3, 1.17.4, 1.18.1)
ERROR: No matching distribution found for numpy==1.17.0 (from mango==1.0.0)

Seems that there is a restriction on version of numpy. My numpy version is 1.18.4 and I do not have the option of degrading the numpy. Do you have any suggestions to resolve the installation issue?
Is it ok that I change the requirements? Does it affect the whole package?

Thank you.

Obtain additional output parameters from the objective function

Hi,
I was exploring this library and it is very nice and intuitive to use! I have a question though:

In my objective function I'm calling another function that returns many variables, including the one I want to optimise. Is there a way in which I can save those results?

The code I'm using is something like the following snippet:

defined_space= {}

results = []
def funct(a,b,c):
do stuff
return loss, other_params

def objective(**params):
loss, other_params = funct(**params)
results.append(other_params)
return loss

tuner = Tuner(space, objective)

When I run mango, the list "results" is still empty even when I'm appending information every time I call the objective function. How can I save "other_params"?

Thank you a lot for your help!

more iteration than setting

Hi,

When I set the num_iteration is 50, the actual running iteration is more than 50:

config = dict()
config["optimizer"] = "Bayesian"
config["num_iteration"] = 50

tuner = Tuner(HYPERPARAMETERS, 
              objective=run_one_training,
              conf_dict=config) 
results = tuner.minimize()

The MLflow shows it has run 62 iterations:
image

Variable type issue in domain_space.py file

System: Ubuntu 18.04, Python; 3.8.8 (via conda environment), Tensorflow: 2.4.0 (with GPU), numpy: 1.18.5
Error happens when using TF in conjunction with Mango for neural architecture search.

In https://github.com/ARM-software/mango/blob/master/mango/domain/domain_space.py, line 120:

...
                    # we need to see the index where: domain[x] appears in mapping[x]
                    index = mapping_categorical[x].index(domain[x])
...

The variable mapping_categorical[x] automatically changes to numpy array for some iterations and remains as a list for some iterations. This causes an error: "numpy.ndarray() has no attribute index". I am not sure why the variable would return list for some iterations and a numpy array for other iterations. I made a workaround replacing the lines as follows:

...
                    # we need to see the index where: domain[x] appears in mapping[x]
                    if(type(mapping_categorical[x]).__name__ == 'list'):
                        index = mapping_categorical[x].index(domain[x])
                    else:
                        index = mapping_categorical[x].tolist().index(domain[x])
...

AttributeError when SARIMAX() is used

IMG_6268

Can someone explain why is my domain a numpy.ndarray object when it clearly is a dictionary assuming domain refers to the param_space dictionary. Otherwise, would appreciate if someone could explain what the error in the image is about?

In gist, error encountered in line on “for x in sorted(domain.keys()):” of domain_space.py’s “convert_GP_space(self,domain_list)” and the error is “AttributeError: ‘numpy.ndarray’ object has no attribute ‘keys’ “

Nested arguments in search space

Sometimes when defining parameters there is some dependency between the parameters. Meaning if one parameter has a specific value, another parameter needs to be supplied that otherwise would'nt.

For example, if we look at SVM, we only need to specify gamma when kernel is ‘rbf’, ‘poly’ or ‘sigmoid’.

If there isn't a way to specify that, then the algorithm can "waste" execution time on settings that don't make sense.

So my question is, is there a way to define a nested search space to create these kind of dependencies? Hyperopt supports this use case

Bayesian Learning constant increase time between iterations, search space & memory constraint

Hello,

First of all, thanks for the KMeans fix in the master branch, it fixed the scikit-learn>=0.23 issue.

Right now, I can't really use the Bayesian optimizer since most of the time spent for every iterations is not spent in the objective function (in my case celery tasks) but in the analysis of their results, a time that is increasing linearly after every iteration.

To decide between Bayesian or Random optimization, if one count only the number of iterations, then the Bayesian optimizer is a clear winner because of its fast convergence, but from a duration perspective, Random optimizer is an order of magnitude better, at least with my dataset / search space. When the batch of celery tasks is finished, I see only one processor used at 100% (so the bottleneck is a mono-threaded process) during several minutes, and this time (idle time from a celery perspective) is increasing linearly, iteration after iteration.
For instance:

  • iteration 1: 124s/it
  • iteration 2: 168s/it
  • iteration 3: 239s/it
  • iteration 4: 329s/it
  • etc.

The very same search space using the Random optimizer displays a constant duration :

  • iteration 1: between 100 and 140s/it (which is approximately the time the celery task batch takes with full usage of the celery workers)
  • [...]
  • iteration 100: between 100 and 140s/it

Also, Bayesian optimizer seems to not handle lots of parameters in the search space, whereas random (which is quite obvious) can by a lot. If I try to do a bayesian search on a large search space, I get an out of memory error very quickly (even on a 256GB RAM server where the mango process is launched ; i.e. it's not a celery memory constraint at all).

So, with my very limited python optimization knowledge, I tried to improve the bayesian module by doing some metering, discovering that the Kmeans algorithm was not responsible for this linear analysis time increase, but most probably the GaussianProcessRegressor / multi-arm bandit functions themselves were.

I tried adding the numba @njit or @jit decorators which brings easily just in time compilation optimization, but most methods of the BayesianLearning class don't support it without modifications, and the ones that accept it did not lead to a significant improvement.

Are you aware of such limitations? Is there some room for improvement regarding monothreaded processing time and large search space support without memory constraint?

Relying right now on the Random optimizer brings me to a last question: how better it is compared to a RandomGridSearch from scikit-learn for instance? Looking at the code, it seems there is no clustering involved, right? So no real intelligence so to speak in the tested parameters, iteration after iteration.

Thanks!

setting checkpoints

As the server I used is with the Slrum system and limited the running time for each job to 2 days, is there any way that can set the checkpoints and then continue to search the parameters in another job submission based on the last job results?

Initial points with values and resuming optimizer

Thanks for making this great piece of software. It's been working flawlessly in my tests.

Now that it's possible to specify custom initial points (#47), I have two questions that are somewhat related to this.

  1. Is it also possible to provide function values for the custom initial points? In many cases, for whatever reason, some function values might be known before running the optimization loop. It would be nice if this information could be used, as a single function call could take hours to complete.
  2. Is there any way to save the state of an optimization to disk (after it's finished or possibly even periodically during the run) and resume at a later time? Right now, as far as I can tell, runBayesianOptimizer always starts from scratch, ignoring whatever is in tuner.results.

'Parallel' object is not iterable

Hello and thanks for this project! It seems very promising!

I am trying to train a xgboost classifier.

My code is:


import pandas as pd
import numpy as np
import xgboost as xgb
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.model_selection import StratifiedKFold
from scipy.stats import uniform
from mango.domain.distribution import loguniform
from mango import Tuner
from joblib import Parallel, delayed

xgb_params = {
    'n_estimators': range(10, 200, 50), # 10 to 200 in steps of 50
    'max_depth': range(1, 15), # 1 to 14
    'reg_alpha': loguniform(-3, 6),  # 10^-3 to 10^3
    'booster': ['gbtree', 'gblinear'],
    'colsample_bylevel': uniform(0.05, 0.95), # 0.05 to 1.0
    'colsample_bytree': uniform(0.05, 0.95), # 0.05 to 1.0
    'learning_rate': loguniform(-3, 3),  # 0.001 to 1
    'reg_lambda': loguniform(-3, 6),  # 10^-3 to 10^3
    'min_child_weight': loguniform(0, 2), # 1 to 100
    'subsample': uniform(0.1, 0.89), # 0.1 to 0.99
}
 
class MangoParallelOptimization:
    def __init__(self,
                 njobs, 
                 configuration_params,
                 features_train,
                 target_train,
                 features_val,
                 target_val):
        self.njobs = njobs
        self.conf_dict = configuration_params
        self.x_train = features_train
        self.y_train = target_train
        self.x_val = features_val
        self.y_val = target_val
        self.space = xgb_params
        
        
    def _objective(self, **model_params):
        kfold = StratifiedKFold(n_splits=2, shuffle=True, random_state=123)
        results = []
        for hyper_param in model_params:
            model = xgb.XGBClassifier(**hyper_param)
                                      
            result = cross_val_score(model, 
                                     self.x_train,
                                     self.y_train,
                                     scoring='accuracy',
                                     cv=kfold).mean()
            results.append(result)
        return results
        
           
    def _objective2(self, params_batch):
        global parameters
        results_batch = Parallel(self.njobs,
                                 backend='multiprocessing')
        (delayed(self._objective)(**params) for params in params_batch)
        acc = [result for result in results_batch]
        return acc
    
    def mango_optimization(self):
        tuner = Tuner(self.space, self._objective2, self.conf_dict)
        optimization_results = tuner.maximize()
        return optimization_results['best_params'], optimization_results['best_objective']
    
    
    
if __name__=="__main__":
    df = pd.read_csv('/home/ggous/example.csv')
    df.dropna(axis=1, inplace=True)
    features = df.drop(['id', 'CLASS'], axis=1)
    labels = df['CLASS'].values
    
    # Split the data into training and testing sets
    x_train, x_test, y_train, y_test = train_test_split(
        features,
        labels,
        stratify=labels,
        test_size = 0.2,
        random_state = 123)
    
    # encode string class values as integers
    label_encoder = LabelEncoder()
    y_train = label_encoder.fit_transform(y_train)
    y_test = label_encoder.transform(y_test)

    scaler = StandardScaler()
    x_train_sc = pd.DataFrame(scaler.fit_transform(x_train),
                              index=x_train.index, 
                              columns=x_train.columns)
    x_test_sc = scaler.transform(x_test)

    # Parallel optimization with Mango
    config_params = {'num_iteration': 40, 'initial_random': 10}
    optim = MangoParallelOptimization(njobs=4,
                                                            configuration_params=config_params,
                                                            features_train=x_train, 
                                                            target_train=y_train,
                                                            features_val=x_test,
                                                            target_val=y_test)
     
    best_parameters, best_objective = optim.mango_optimization()

    # Results
    print('best parameters:', best_parameters)
    print('best accuracy:', best_objective)
    # Train the model with the best hyper-parameters 
    best_model = xgb.XGBClassifier(n_jobs=-1, **best_parameters)
    best_model.fit(x_train, y_train)

The file I am using is here.

I have some questions:

  1. First of all, running the code , gives : Parallel object is not iterable

  2. If I want to use in the xgb classifier, the following arguments:

'use_label_encoder': False,
'eval_metric': 'mlogloss',
'seed': 123,
'enable_categorical': False

Can I do ?? :

for hyper_param in model_params:
            model = xgb.XGBClassifier(**hyper_param, 
                                                       use_label_encoder'=False,
                                                       eval_metric= 'mlogloss',
                                                       seed= 123,
                                                       enable_categorical= False )
  1. If I want to manually do the k fold , like this:
def _objective(self, **model_params):
  kfold = StratifiedKFold(n_splits=2, shuffle=True, random_state=123)
  for i, (train_idx, val_idx) in enumerate(kfold.split(x_train, y_train)):
      x_train_, y_train_ = x_train[train_idx, :], y_train[train_idx]
      x_val_, y_val_ = x_train[val_idx, :], y_train[val_idx]
          
      model = xgb.XGBClassifier(**hyper_param) 
  
      history = model.fit(x_train_,
                          y_train_,
                          early_stopping_rounds=10,
                          eval_set=[(x_train_, y_train_), (x_val_, y_val_)])
      
      ....

How can I do that? And use the history object inside every fold iteration in order to plot things.
And finally return the result that mango wants.?
What kind of result should be?

Domain error in loguniform

Hi,
seems that there is a problem with loguniform when one of its argument is negative. For example, my code is runnable when the first argument of loguniform is positive and it generates domain error when the first argument is a negative number. Any thought on this?

Issue with Constrained Optimization

Hello,

We are working on a project that involves constrained optimization. I found the following error that occurs when using a constraint. Here is the example:

from mango import scheduler, Tuner
from scipy.stats import uniform
import numpy as np

np.random.seed(42)

# Search space
param_space = dict(x=uniform(-10, 20))

x_min = -2
x_max = 2

# Quadratic objective Function
@scheduler.serial
def objective(x):
    return x * x

def constraint(samples):
  '''
      Given a list of samples (each sample is a dict with parameter names as keys)
      Returns a list of True/False elements indicating whether the corresponding sample
      satisfies the constraints or not
  '''

  x = np.array([s['x'] for s in samples])
  return (x <= x_max) & (x >= x_min)

conf_dict = dict(
    constraint = constraint,
    domain_size = 1000,
    initial_random = 1,
    num_iteration  = 15
)

# Initialize and run Tuner
tuner = Tuner(param_space, objective, conf_dict)


for i in range(100):

    result = tuner.minimize()
    print(f'Optimal value of parameters: {result["best_params"]}.')



The optimizer operates successfully for a number of iterations but then exits with the following error:

----------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
[<ipython-input-19-739aa7b673c8>](https://localhost:8080/#) in <cell line: 39>()
     39 for i in range(100):
     40 
---> 41     result = tuner.minimize()
     42     print(f'Optimal value of parameters: {result["best_params"]}.')
     43 

2 frames
[/usr/local/lib/python3.10/dist-packages/mango/tuner.py](https://localhost:8080/#) in minimize(self)
    158     def minimize(self):
    159         self.maximize_objective = False
--> 160         return self.run()
    161 
    162     def process_initial_custom(self):

[/usr/local/lib/python3.10/dist-packages/mango/tuner.py](https://localhost:8080/#) in run(self)
    145     def run(self):
    146         if self.config.is_bayesian:
--> 147             self.results = self.runBayesianOptimizer()
    148         elif self.config.is_random:
    149             self.results = self.runRandomOptimizer()

[/usr/local/lib/python3.10/dist-packages/mango/tuner.py](https://localhost:8080/#) in runBayesianOptimizer(self)
    310 
    311             results["best_objective"] = np.max(results["objective_values"])
--> 312             results["best_params"] = results["params_tried"][
    313                 np.argmax(results["objective_values"])
    314             ]

IndexError: index 8 is out of bounds for axis 0 with size 8

Thank you for your help, and we appreciate any suggestions you have for resolving these issues.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.