Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

simple workflow under python #116

Open
nikohansen opened this issue Feb 11, 2015 · 23 comments
Open

simple workflow under python #116

nikohansen opened this issue Feb 11, 2015 · 23 comments
Assignees

Comments

@nikohansen
Copy link
Collaborator

My most common use-case when applying CMA-ES in Python or Octave looks something like this

import cma
res = cma.fmin(some_function, 20 * [1], 1)
cma.plot()

If the optimization takes longer, I will open a second Python shell to do the plotting "online". This works, because cma.plot() reads in the output written on disc. cma.plot('cma_data_on_some_function') would plot the respective data (cma.fmin must have been called with the respective output filename option). Can we established a similar use-case with lcmaes?

@beniz beniz self-assigned this Feb 12, 2015
@beniz beniz added the python label Feb 12, 2015
@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

Yes, this almost exactly what I do with the C++ exe: opening a second shell allows to look at the plot while optimization is still running. Let's see how to do this with the python bindings, the first part is rather easy:

import lcmaes
p = lcmaes.make_simple_parameters(x,sigma,lambda_,seed)
p.set_fplot(filename)
cmasols = lcmaes.pcmaes(some_function,p)

The main difference I see between your example and using the libcmaes Python bindings is that at the moment the plot function is outside the bindings, so we cannot yet do lcmaes.plot(). The current plotting script for libcmaes is actually in Python, in tests/cma_multiplt.py.

In order to add the missing line:

lcmaes.plot(filename)

I need to add pure Python code into the Boost-python generated code. I did check and this appears possible with some work.

Another simple though less elegant solution would be for me to refactor cma_multiplt.py slightly so that it could be imported and used as something like:

import lcmaesplt
lcmaesplt.plot(filename)

I believe you would need a filename anyways since there's no default file yet.

Another option could be based on #110, thus allowing to use your existing plotting script.

Finally, at the moment you can run the optimization in Python using lcmaes and plot the results online with cma_multiplt.py from another shell, which fits your second use case, not the first one:

python tests/cma_multiplt.py filename

My preference goes to adding the plot(filename) function to lcmaes and I can report about this in this ticket.

@nikohansen
Copy link
Collaborator Author

I have no objections to another import, so adding plot to lcmaes directly is IMHO not necessary (unless desired otherwise). Let me see if I find some time to check how cma_multiplt.py must be modified to cover both use cases. It's not uncommon in Python to run a file either as script or as import.

@nikohansen
Copy link
Collaborator Author

Regarding

p = lcmaes.make_simple_parameters(x, sigma, lambda_, seed)

I think the burden of setting lambda_ should not be on the user by default (I guess this question is independent of the python interface).

I believe the last line of the example should read:

cmasols = lcmaes.pcmaes(lcmaes.fitfunc_pbf.from_callable(some_function), p)

or

fct = lcmaes.fitfunc_pbf.from_callable(some_function)
cmasols = lcmaes.pcmaes(fct, p)

EDIT: lambda should be exposed that it can be set easily, but we do have a perfectly valid default value available, such that a user who has no clue about evolutionary algorithms don't need to dig into it. Users already have the burden to understand what sigma means.

@nikohansen
Copy link
Collaborator Author

I am still rooting for conversion to legacy format being available, as I have additional functionalities (e.g. cma.disp) at my disposal in this case.

@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

I have no objections to another import, so adding plot to lcmaes directly is IMHO not necessary (unless desired otherwise)

OK, this is actually simpler (anything that doesn't require dealing with boost-python is simpler...)

I think the burden of setting lambda_ should not be on the user by default

Yes, and the Python behavior here differs from the C++ API one because I need to figure out how to pass default arguments with Boost-python. This is a pure engineering problem, and I've looked it up, so it is now a task.

(links for my own ref, http://stackoverflow.com/questions/6050996/boost-python-overloaded-functions-with-default-arguments-problem and http://www.boost.org/doc/libs/1_37_0/libs/python/doc/v2/overloads.html and http://boost.cppll.jp/HEAD/libs/python/doc/tutorial/doc/default_arguments.html )

@nikohansen
Copy link
Collaborator Author

I see, a simple solution would be that None and/or 0 and/or False and/or -1 expand to the default.

@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

-1 expand to the default

It already does this. I am working on using the boost python overload macros right now, but along with templates, this is not compiling for the most complicated cases for now... I've successfully tackled the make_simple_parameters function to be called as

p = lcmaes.make_simple_parameters(x,sigma)

or

p = lcmaes.make_simple_parameters(x,sigma,lambda_,seed)

beniz pushed a commit that referenced this issue Feb 12, 2015
@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

The fix above allows support for default arguments to make_simple_parameters, make_parameters_nb and make_parameters_pwb that allow to create parameters for geno/pheno transforms without and with bounds (constraints). Combinations of such constructors with default lambda and seed for linear scaling (make_parameters_ls and make_parameters_pwq_ls) are impossible due to bug in Boost Python that fails to recognize a template with comma in Boost macro:

lcmaes.cc:210:1: error: ‘BOOST_PYTHON_FUNCTION_OVERLOADS’ does not name a type
 BOOST_PYTHON_FUNCTION_OVERLOADS(make_parameters_default_ls,make_parameters<GenoPheno<NoBoundStrategy,linScalingStrategy>>,3,5)

I don't believe this is too problematic as in these cases lambda=-1 and seed=0 activate default internal values.

@nikohansen
Copy link
Collaborator Author

FYI, my Python kernel dies when I use 0 instead of -1 for lambda.

beniz pushed a commit that referenced this issue Feb 12, 2015
Conflicts:
	tests/cma_multiplt.py
@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

Python kernel dies when I use 0 instead of -1 for lambda

Yes, good point, this is in the lib, making a dedicated ticket. Also, is lambda=1 a potentially legitimate value ? I believe I haven't accommodated for lambda < 2.

@nikohansen
Copy link
Collaborator Author

lambda=1 could in general be useful/legitimate with elitism, but I actually never tried it.

@beniz
Copy link
Collaborator

beniz commented Feb 12, 2015

I actually never tried it

my curiosity is picked :) I thought of it with gradient a few months ago, as I was curious of how a particular run would do with the gradient offspring only.

@nikohansen
Copy link
Collaborator Author

The main problem is step-size control. TPA needs two additional samples. Unmodified CSA produces probably far too small step-sizes. This can be fixed in some way or the other (and the famous 1/5th success rule is always available).

@beniz
Copy link
Collaborator

beniz commented Feb 13, 2015

Here is my current minimal Python workflow given the few additions and fixes (on 'dev' branch):

import lcmaes
import cma_multiplt as lcmaplt
x = [10]*10
sigma = 0.1
p = lcmaes.make_simple_parameters(x,sigma)
p.set_str_algo("acmaes")
p.set_fplot('simple.dat')

# objective function.                                                                                                                                
def nfitfunc(x,n):
    val = 0.0
    for i in range(0,n):
        val += x[i]*x[i]
    return val

# pass the function and parameters to cmaes, run optimization and collect solution object.                                                            
cmasols = lcmaes.pcmaes(lcmaes.fitfunc_pbf.from_callable(nfitfunc),p)
lcmaplt.plot('simple.dat')

Note that I've moved cma_multiplt.py from tests/ to python/ repository as it makes better sense now.

EDIT: the minimal workflow is now in python/simple.py, and I will update the doc as well.

@nikohansen
Copy link
Collaborator Author

Excellent, I also like a lot that the docs now appear in the Python objects! A small gimmick to further shorten the example:

def nfitfunc(x, n):
    assert len(x) == n  # not necessary
    return sum([y**2 for y in x])

or even

nfitfunc = lambda x, n: sum([y**2 for y in x])

If you insist in using n, sum([x[i]**2 for i in range(n)]) can replace the above sum in both cases. The magic construct is called list comprehension.

@nikohansen
Copy link
Collaborator Author

cma_multiplt.py apparently disappeared altogether.

@beniz
Copy link
Collaborator

beniz commented Feb 14, 2015

It is in python/ now.

@beniz
Copy link
Collaborator

beniz commented Feb 14, 2015

You are right that somehow it isn't. Fixing it now.

@beniz
Copy link
Collaborator

beniz commented Feb 14, 2015

Not sure what happened, this should be fixed with 328bd00

@nikohansen
Copy link
Collaborator Author

I am sure that's a stupid problem, but I don't find a bottom to keep my fork up-to-date with your repo.

@beniz
Copy link
Collaborator

beniz commented Feb 14, 2015

Not sure what you mean. On branch dev, a git pull should fix the missplacement of the plotting script.

@nikohansen
Copy link
Collaborator Author

Sorry, I mean my fork on github, operating from within the browser (not specifically related to the plotting script). But even from a local fork, I wouldn't know how to sync it with its origin. Maybe it's just not meant to work like this.

beniz pushed a commit that referenced this issue Feb 20, 2015
beniz pushed a commit that referenced this issue Feb 20, 2015
@beniz
Copy link
Collaborator

beniz commented Feb 23, 2015

Just merged the lcmaes_interface.py stuff into 'dev' branch, readying it for next release. Also, the documentation at https://github.com/beniz/libcmaes/wiki/Python-bindings has been updated with the new simplified interface.

EDIT: I believe this should fulfill this ticket

andrewsali pushed a commit to andrewsali/libcmaes that referenced this issue Jan 31, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants