MLBazaar/BTB

Tuner re-proposes already-tried parameters

StaffanAldenfalk opened this issue · 3 comments

I use the one two three steps on the site and have noticed that if i specify my tunables as:

tunables = [
    ('dropout_precentage1', HyperParameter(ParamTypes.INT, [40, 50])),
    ('dropout_precentage2', HyperParameter(ParamTypes.INT, [40, 50]))
]

Where the range on each parameter is only 10 values, it will do two guesses, for example [44, 46] and [48,42] and then continue to run the one of them which gave the best result. So if [44,46] gave the best results it will continue to propose the variables [44,46] for all of my iterations.

Which tuner class are you using? And are you able to provide the scores that you passed to the tuner that led to this behavior?

Here is a reproducible example:

import random
import sys
from collections import Counter

import numpy as np

from btb import HyperParameter
from btb.tuning import GP

if len(sys.argv) == 2:
    n = int(sys.argv[1])
else:
    n = 10

np.random.seed(1)
random.seed(1)

tunables = [
    ('a', HyperParameter('int', [0, 5])),
    ('b', HyperParameter('int', [0, 5])),
]

tuner = GP(tunables)

counter = Counter()
for _ in range(n):
    params = tuner.propose()
    tuner.add(params, 1.0)
    counter.update([tuple(sorted(params.items()))])

print(counter)

Produces:

Counter({(('a', 2), ('b', 3)): 2, (('a', 2), ('b', 5)): 1, (('a', 4), ('b', 5)): 1, (('a', 2), ('b', 1)):
1, (('a', 5), ('b', 1)): 1, (('a', 1), ('b', 1)): 1, (('a', 0), ('b', 1)): 1, (('a', 4), ('b', 2)): 1, (('a', 3), ('b', 4)): 1})

With 10 iterations and 36 combinations of a/b, there should be no reason to try {'a': 2, 'b': 3} twice.

With the new re-implementation, issues #131 #132 #133 #134 , this problem is fixed. The Tuner will give you new combinations only, unless passing the argument allow_duplicates=True when calling tuner.propose. However, the tuner can't propose more than the tunable cardinality.
A short example is shown below:

from btb.tuning import GPTuner, IntHyperParam, Tunable

tunable = Tunable({
    'a': IntHyperParam(40, 50),
    'b': IntHyperParam(40, 50)
})

tuner = GPTuner(tunable)

tuner.propose(tunable.cardinality)  # This will work and will generate 121 combinations
tuner.propose(tunable.cardinality + 1)  # This will raise a value error
tuner.propose(tunable.cardinality + 1, allow_duplicates=True)  # This will work and will generate 122 combinations with repeated values

Bear in mind that the tuner will generate a random combination until we don't use record, also after recording n amounts of combinations, the tuner will be able to propose tunable.cardinality - n combinations.