0

I'm having a problem on using @use_named_args from Scikit Optimize. The problem is that my objective function accepts the arguments NamedTuple and I can't change this because this is the requirement in the project I'm working on. Now, I need to implement skopt for hyperparameters search and I need to use @use_named_args to decorate my objective function. How can I do it since my objective function accepting NamedTuple instead of single arguments (like the one on skopt example)? I also need to pass a fixed hyperparameters set in addition to the variable hyperparameters that I need to tune.

Below is the code I want to achieve, but I can't because I can't decorate my_objective_function with @use_named_args

from skopt.space import Real
from skopt import forest_minimize
from skopt.utils import use_named_args
from functools import partial

dim1 = Real(name='foo', low=0.0, high=1.0)
dim2 = Real(name='bar', low=0.0, high=1.0)
dim3 = Real(name='baz', low=0.0, high=1.0)

dimensions = [dim1, dim2, dim3]

class variable_params(NamedTuple):
    bar: int
    foo: int
    baz: int

class fixed_params(NamedTuple):
    bar1: int
    foo1: int
    baz1: int

# Instantiate object
variable_args = variable_params(foo=5, bar=10, baz=2)
fixed_args = fixed_params(foo1=2, bar1=3, baz1=4)


@use_named_args(dimensions=dimensions)
def my_objective_function(v_args, f_args):
    return v_args.foo ** 2 + v_args.bar ** 4 + v_args.baz ** 8 + f_args.foo1 * 2 + f_args.bar1 * 4 + f_args.baz1 * 8

#Do partial function for passing the fixed params
my_objective_function = partial(my_objective_function,f_args=fixed_args)

result = forest_minimize(
    func=my_objective_function, 
    dimensions=dimensions, 
    n_calls=20, 
    base_estimator="ET",
    random_state=4
)

Thank you!

1
  • could you not unpack the arguments for variable_args inside the objective? Commented Jun 9, 2021 at 11:22

1 Answer 1

1

You can just create a new objective function to be passed to the optimizer. It will receive the variable parameters, convert those to a named tuple and then call the original objective.

Slightly adjusting your example you get something like:

from skopt.space import Real
from skopt import forest_minimize
from skopt.utils import use_named_args
from collections import namedtuple

dim1 = Real(name='foo', low=0.0, high=1.0)
dim2 = Real(name='bar', low=0.0, high=1.0)
dim3 = Real(name='baz', low=0.0, high=1.0)

dimensions = [dim1, dim2, dim3]

VariableParams = namedtuple('VariableParams', 'foo bar baz')
FixedParams = namedtuple('FixedParams', 'foo1 bar1 baz1')

# define fixed params
fixed_args = FixedParams(foo1=2, bar1=3, baz1=4)


# objective you are not allowed to change
def my_objective_function(v_args, f_args):
    return v_args.foo ** 2 + v_args.bar ** 4 + v_args.baz ** 8 + f_args.foo1 * 2 + f_args.bar1 * 4 + f_args.baz1 * 8


# new objective passed to the optimizer
@use_named_args(dimensions)
def objective(foo, bar, baz):
    variable_args = VariableParams(foo, bar, baz)
    return my_objective_function(variable_args, fixed_args)


# run search with new objective
result = forest_minimize(
    func=objective,
    dimensions=dimensions,
    n_calls=10
)

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.