1

I´m currently trying to find the minimum of some function f(arg1, arg2, arg3, ...) via Gaussian optimization using the GPyOpt module. While f(...) takes many input arguments, I only want to optimize a single one of them. How do you do that?

My current "solution" is to put f(...) in a dummy class and specify the not-to-be-optimized arguments while initializing it. While this is arguably the most pythonesque way of solving this problem, it`s also way more complicated than it has any right to be.

Short working example for a function f(x, y, method) with fixed y (a numeric) and method (a string) while optimizing x:

import GPyOpt
import numpy as np

# dummy class
class TarFun(object):
    # fix y while initializing the object
    def __init__(self, y, method):
        self.y = y
        self.method = method
    # actual function to be minimized
    def f(self, x):
        if self.method == 'sin':
            return np.sin(x-self.y)
        elif self.method == 'cos':
            return np.cos(x-self.y)

# create TarFun object with y fixed to 2 and use 'sin' method
tarFunObj = TarFun(y=2, method='sin')
# describe properties of x
space = [{'name':'x', 'type': 'continuous', 'domain': (-5,5)}]
# create GPyOpt object that will only optimize x
optObj = GPyOpt.methods.BayesianOptimization(tarFunObj.f, space)

There definitely has to be a simpler way. But all the examples I found optimize all arguments and I couldn't figure it out reading the code on github (I though i would find the information in GPyOpt.core.task.space , but had no luck).

Andrei
  • 55,890
  • 9
  • 87
  • 108
Leander Moesinger
  • 2,449
  • 15
  • 28

2 Answers2

1

I would check out the partial function from the functools standard library. It allows you to partially specify a function, so for example:

import GPyOpt
import numpy as np
from functools import partial


def f(x, y=0):
    return np.sin(x - y)


objective = partial(f, y=2)
space = [{'name': 'x', 'type': 'continuous', 'domain': (-5, 5)}]

opt = GPyOpt.methods.BayesianOptimization(
    objective, domain=space
)
  • Definitely a cleaner workaround than what i was doing, but i still think there has to be a way to directly specify this in the `GPyOpt` object (fixing arguments seems way too important to require an external module) – Leander Moesinger Aug 09 '18 at 08:32
  • You could also simply add a variable of type `discrete` to your space, like so: `{'name': 'y', 'type': 'discrete', 'domain': (2,)}` – Theodore Ando Aug 09 '18 at 15:00
  • That would work in this specific example, but e.g. if a function takes a string as argument this won't work. Of course you could then encode the string as integer, but that's again very messy. – Leander Moesinger Aug 09 '18 at 15:30
1

GPyOpt supports this natively with context. You describe the whole domain of your function, and then fix values of some of the variables with a context dictionary when calling optimization routine. API looks like that:

myBopt.run_optimization(..., context={'var1': .3, 'var2': 0.4})

More details can be found in this tutorial notebook about contextual optimization.

Andrei
  • 55,890
  • 9
  • 87
  • 108