Hyperopt是否支持选择的子集?

时间:2018-07-16 17:49:36

标签: python hyperopt

我有一组选择 A 。我想找回选项 A 的子集。 Hyperopt可以做到这一点吗?

输入:

{
    'A': hp.choice('A', [0, 1, 2, 3])
}

输出:

{
    'A': [0, 2]
}

1 个答案:

答案 0 :(得分:1)

No, but if you specifically want that functionality, there are multiple ways to do so.

  1. You can define a new expression and add it to existing hyperopt parameter expressions as given in the documentation. For example, in your case, you can do:

    import hyperopt.pyll
    from hyperopt.pyll import scope
    from hyperopt.pyll.stochastic import sample
    
    # Add a new method as you want
    @scope.define
    def foo(choices, num_choices):
        return np.random.choice(choices, size=num_choices, replace=False)
    
    choices = [1,2,3,4]
    
    # Define the space like below and use in fmin
    space = scope.foo(choices, 2)
    
    # Call this multiple times to see how space behaves
    print(sample(space))   
    

    See the documention of numpy.random.choice to know how that works.

    Note:

    • The foo method will return a subset of choices (in a numpy array). So make sure that in your objective function, you are using the internal multiple values like x[0], x[1], ... etc.
    • Add scope.undefine(foo) in the end of your code, or else you will have to restart your terminal / kernel each time before running the code.
    • The hyperopt wiki specifically prohibits to define new types of parameter search spaces just as we did above because that may affect the search strategy or perform non-optimally.
  2. If you are allowed to choose two values with replacement (that means that sometimes both values in the subset will be same. This is the reason we used replace=False in point 1), then the following can be done:

    choices = [1,2,3,4]
    space = [hp.choice('c1', choices), 
             hp.choice('c2', choices)]
    

    Then in your objective function, you can access your two values as x[0], x[1].

    But from your question, it seems like you want to have the sub-choices and that implies without replacement, so a sub-set of [1,1] or [2,2] etc. is invalid. In that case, you should use the Trials object to define status.

A sample program for point 2 is below:

from hyperopt import fmin, tpe, hp, STATUS_OK, STATUS_FAIL, Trials

def objective(x):
    # Check if the supplied choices are valid or not
    x1 = x[0]
    x2 = x[1]
    if x1 == x2:
        # If invalid, only return the status and hyperopt will understand
        return {'status': STATUS_FAIL} 


    # Normal flow of objective
    # Do your coding here

    # In the end, return this  
    return {
        'loss': actual_loss,  # Fill the actual loss here
        'status': STATUS_OK
        }

choices = [1,2,3,4]
space = [hp.choice('c1', choices), 
         hp.choice('c2', choices)]

trials = Trials()   
best = fmin(objective, space=space, algo=tpe.suggest, max_evals=100, trials=trials)

from hyperopt import space_eval
print(space_eval(space, best))

Hope this helps.