facebookresearch / nevergrad

A Python toolbox for performing gradient-free optimization
https://facebookresearch.github.io/nevergrad/
MIT License
3.94k stars 353 forks source link

Inability to update Optimizer's Parameters Bound #1591

Closed devin-lee closed 8 months ago

devin-lee commented 8 months ago

This is a discussion regarding the parameter configuration where the bounds input specified are frozen during optimization stage, and hence is unable to change during the iterations. At face value, I think that users should be allowed to change it to reflect a newer state of the optimization progress wherever applicable.

Reproduce

Input:

import nevergrad as ng

param = ng.p.Instrumentation(parameter = ng.p.Array(shape = (2,), lower = [.01, 1.53], upper = [.49, 2.23]))
optimizer = ng.optimizers.ConfPSO()
optimizer = optimizer(parametrization = param)

Output: optimizer.parametrization[1]['parameter'].bounds

Result

The output mentioned above would produce the following: (array([0.01, 1.53]), array([0.49, 2.23]))

Which is a tuple, an immutable type. Now, this isn't an issue as this is purely a design choice.

But why is a dynamical bound update not available (unless I missed it somewhere in the documentation?), there are situations where parameter search space may be constantly fluctuating and the initial specification for (lower, upper) may no longer be fully relevant, so having the optimizer to parse through the irrelevant search space don't seem efficient to me.

I may want to do something like:

for _ in range(optimizer.budget):
   ...
   optimizer.parametrization[1]['parameter'].bounds[0] = np.array([dynamicVal_1, dynamicVal_2])
   optimizer.parametrization[1]['parameter'].bounds[1] = np.array([dynamicVal_3, dynamicVal_4])
   ...

But given the current output type is based on tuple, it would be infeasible. Although changing one line of bounds function from https://github.com/facebookresearch/nevergrad/blob/main/nevergrad/parametrization/data.py return bounds -> return list(bounds) would make it a list instead of tuple, and therefore mutable.

Question

Unfortunately, I don't have the full depth knowledges across all the optimizers available, so I just would like to understand if this is because of some algorithms unable to handle bound changes during optimization (or some other technical reasons), or something else, and therefore not implemented (or is actually possible in Nevergrad -- I just didn't realize it)? Thanks!

Edit: Alright, just read that NG has a spawn child function to inform decisions. So, asides of the concern on border effects, suppose we update the change to bound directly, what would happen to candidates that resides in out-of-new-bound region?

devin-lee commented 8 months ago

Self answer: Providing setting in child spawned can inform decision to make candidates move towards it. Cheap constraint registration can also ensure candidate to mutate to fit right for the constraint specified.