SimonBlanke / Hyperactive

An optimization and data collection toolbox for convenient and fast prototyping of computationally expensive models.
https://simonblanke.github.io/hyperactive-documentation
MIT License
512 stars 42 forks source link

AttributeError can't pickle local function object #44

Closed mlittmanabbvie closed 2 years ago

mlittmanabbvie commented 2 years ago

Look into the FAQ of the readme. Can the bug be resolved by one of those solutions? No

Describe the bug When using multiple optimizers and passing a local function, I am getting the error listed below.

Code to reproduce the behavior

import pandas as pd
from hyperactive import Hyperactive
from hyperactive import RepulsingHillClimbingOptimizer, BayesianOptimizer

def f():
    def optimization_func(opt):
        return 5 

    h = Hyperactive(["progress_bar", "print_results", "print_times"])
    search_space = {
        "exp": list(range(0, 5)),
        "slope": list(np.arange(0.001, 10, step=0.05)),
        "clust": [5]
    }

    h.add_search(
        optimization_func,
        search_space=search_space,
        n_iter=10,
        optimizer=RepulsingHillClimbingOptimizer(
            epsilon=0.05,
            distribution="normal",
            n_neighbours=3,
            rand_rest_p=0.03,
            repulsion_factor=3,
        ),
        n_jobs=1,
        max_score=None,
        initialize={
            "warm_start": [
                {
                    "exp": 2,
                    "slope": 5,
                    "clust": 5
                }
            ]
        },
        early_stopping={"tol_rel": 0.001, "n_iter_no_change": 3},
        random_state=0,
        memory=True,
        memory_warm_start=None,
    )
    h.add_search(optimization_func,search_space = search_space,n_iter = 10)
    h.run()

f()

Error message from command line

AttributeError                            Traceback (most recent call last)
<ipython-input-21-5522e445d18f> in <module>
     45     h.run()
     46 
---> 47 f()

<ipython-input-21-5522e445d18f> in f()
     43     )
     44     h.add_search(optimization_func,search_space = search_space,n_iter = 10)
---> 45     h.run()
     46 
     47 f()

~\Anaconda3\lib\site-packages\hyperactive\hyperactive.py in run(self, max_time, _test_st_backend)
    178                 progress_board.open_dashboard()
    179 
--> 180         self.results_list = run_search(
    181             self.process_infos, self.distribution, self.n_processes
    182         )

~\Anaconda3\lib\site-packages\hyperactive\run_search.py in run_search(search_processes_infos, distribution, n_processes)
     49         (distribution, process_func), dist_paras = _get_distribution(distribution)
     50 
---> 51         results_list = distribution(
     52             process_func, process_infos, n_processes, **dist_paras
     53         )

~\Anaconda3\lib\site-packages\hyperactive\distribution.py in multiprocessing_wrapper(process_func, search_processes_paras, n_processes, **kwargs)
     18 ):
     19     pool = mp.Pool(n_processes, **kwargs)
---> 20     results = pool.map(process_func, search_processes_paras)
     21 
     22     return results

~\Anaconda3\lib\multiprocessing\pool.py in map(self, func, iterable, chunksize)
    362         in a list that is returned.
    363         '''
--> 364         return self._map_async(func, iterable, mapstar, chunksize).get()
    365 
    366     def starmap(self, func, iterable, chunksize=None):

~\Anaconda3\lib\multiprocessing\pool.py in get(self, timeout)
    769             return self._value
    770         else:
--> 771             raise self._value
    772 
    773     def _set(self, i, obj):

~\Anaconda3\lib\multiprocessing\pool.py in _handle_tasks(taskqueue, put, outqueue, pool, cache)
    535                         break
    536                     try:
--> 537                         put(task)
    538                     except Exception as e:
    539                         job, idx = task[:2]

~\Anaconda3\lib\multiprocessing\connection.py in send(self, obj)
    204         self._check_closed()
    205         self._check_writable()
--> 206         self._send_bytes(_ForkingPickler.dumps(obj))
    207 
    208     def recv_bytes(self, maxlength=None):

~\Anaconda3\lib\multiprocessing\reduction.py in dumps(cls, obj, protocol)
     49     def dumps(cls, obj, protocol=None):
     50         buf = io.BytesIO()
---> 51         cls(buf, protocol).dump(obj)
     52         return buf.getbuffer()
     53 

AttributeError: Can't pickle local object 'f.<locals>.optimization_func'

System information:

Additional context In the previous question you had mentioned support for pathos. How do I use that in order to run this successfully?

SimonBlanke commented 2 years ago

Hello @mlittmanabbvie,

The api-ref section of the readme and the faq was updated with the new information about pathos. I modified your example to use pathos:

import numpy as np
import pandas as pd
from hyperactive import Hyperactive
from hyperactive import RepulsingHillClimbingOptimizer

def f():
    def optimization_func(opt):
        return 5

    h = Hyperactive(distribution="pathos")
    search_space = {
        "exp": list(range(0, 5)),
        "slope": list(np.arange(0.001, 10, step=0.05)),
        "clust": [5],
    }

    h.add_search(
        optimization_func,
        search_space=search_space,
        n_iter=10,
        optimizer=RepulsingHillClimbingOptimizer(
            epsilon=0.05,
            distribution="normal",
            n_neighbours=3,
            rand_rest_p=0.03,
            repulsion_factor=3,
        ),
        n_jobs=1,
        max_score=None,
        initialize={"warm_start": [{"exp": 2, "slope": 5, "clust": 5}]},
        early_stopping={"tol_rel": 0.001, "n_iter_no_change": 3},
        random_state=0,
        memory=True,
        memory_warm_start=None,
    )
    h.add_search(optimization_func, search_space=search_space, n_iter=10)
    h.run()

f()

This works fine on my system. Let me know if it also works on yours.