CMA-ES / libcmaes

libcmaes is a multithreaded C++11 library with Python bindings for high performance blackbox stochastic optimization using the CMA-ES algorithm for Covariance Matrix Adaptation Evolution Strategy
Other
321 stars 78 forks source link

Python API missing a cmasols.print() ? #146

Open fl2o opened 7 years ago

fl2o commented 7 years ago

LINKED with #135 issue.

Hi @beniz,

I am working with python, using bounded parameters and linear scaling, however the best_candidate parameters are not rescaled with the lcmaes.get_candidate_x(bcand) and I can't find the 'cmasols.print()' function in the python API, neither use the genopheno object.

I struggle implementing it in the python/libcmaes.cc file. Would be grateful for a code snippet or a merge :) thanks in advance!

Florian

beniz commented 7 years ago

Maybe sharing your code would help, first what you are trying to execute, in Python if that's what you are using, along with your attempt to add the print function to the Python bindings.

fl2o commented 7 years ago

Here is the code I am running

    x = [2]*dimension #defaut param lies in [0,10]
    olambda = 50 # lambda is a reserved keyword in python, using olambda instead.
    success = 0
    seed = 0 # 0 for seed auto-generated within the lib.
    sigma = 0.01 #[0.001, 0.1]
    #lower_boundaries equals something like [0.756, 0.251, 0.686, ...]
    gp = lcmaes.make_genopheno_pwqb_ls(lower_boundaries.tolist(), upper_boundaries.tolist(), dimension)
    p = lcmaes.make_parameters_pwqb_ls(x, sigma, gp, olambda, seed)
    p.set_max_iter(1000)
    # objective function.
    p.set_str_algo('sepacmaes')
    # generate a function object
    objfunc = lcmaes.fitfunc_pbf.from_callable(pythonFunc);
    # pass the function and parameter to cmaes, run optimization and collect solution object.
    cmasols = lcmaes.pcmaes_pwqb_ls(objfunc,p)
    bcand = cmasols.best_candidate()
    bx = lcmaes.get_candidate_x(bcand)
    print "best value=", bcand.get_fvalue()
    print "best x=",bx

I am getting correct best fitness value but the parameters associated with it are not rescaled

this is the function i am trying to implement:

  template <class TGenoPheno>
  std::ostream& CMASolutions::print(std::ostream &out,
                    const int &verb_level,
const TGenoPheno &gp) const

I tried to implement it the naive way:

 class_<CMASolutions>("CMASolutions","Object for holding results and intermediate evolving solutions from a running optimizer")
    .def(init<Parameters<GenoPheno<NoBoundStrategy>>&>())
    ...
    ...
    ...
    .def("print", &CMASolutions::print, "rescale bcand parameters")

but I get an error

note : template argument deduction/substitution failed

when executing the make command line.

beniz commented 7 years ago

OK thanks, I see. It's possible that the difficulty is a bit more global, and that access to the solution parameters in original (non distorted) space is not made available easily enough. I just took a quick look at it and can't seriously dig into this immediately.

fl2o commented 7 years ago

Thank you for your quick answer!

Unfortunately, I don't have the skills to make the patch by myself...

Keep me updated when you have the solution or any alternative trick that I could use! Have a good week-end.

nikohansen commented 7 years ago

One option is to do all transformations on the python side.

import numpy as np
class LinearScaling(object):
    """define a scaling of variables.

    Example:

    >>> fun = lambda x: sum(np.asarray(x)**2)
    >>> dim = 8
    >>> s = LinearScaling(range(1, dim + 1))
    >>> fun_scaled_in_fixed_dim = lambda x: fun(s(x))
    >>> print(s(dim * [1]))
    [1 2 3 4 5 6 7 8]

    """
    def __init__(self, scaling_factors):
        self.scaling = np.array(scaling_factors, copy=True)
    def __call__(self, x):
        return self.scaling * x
    def inverse(self, x):
        return self.scaling**-1 * x

For a transformation into boundaries you might consider cma.BoundTransform.repair. The cma package is available on The Python Package Index, using pip install cma.