Spaces:
Running
Running
# Copyright (c) Microsoft Corporation. | |
# Licensed under the MIT license. | |
import logging | |
import time | |
from nni.algorithms.hpo.hyperopt_tuner import HyperoptTuner | |
from .. import Sampler, submit_models, query_available_resources, is_stopped_exec, budget_exhausted | |
from .base import BaseStrategy | |
_logger = logging.getLogger(__name__) | |
class TPESampler(Sampler): | |
def __init__(self, optimize_mode='minimize'): | |
self.tpe_tuner = HyperoptTuner('tpe', optimize_mode) | |
self.cur_sample = None | |
self.index = None | |
self.total_parameters = {} | |
def update_sample_space(self, sample_space): | |
search_space = {} | |
for i, each in enumerate(sample_space): | |
search_space[str(i)] = {'_type': 'choice', '_value': each} | |
self.tpe_tuner.update_search_space(search_space) | |
def generate_samples(self, model_id): | |
self.cur_sample = self.tpe_tuner.generate_parameters(model_id) | |
self.total_parameters[model_id] = self.cur_sample | |
self.index = 0 | |
def receive_result(self, model_id, result): | |
self.tpe_tuner.receive_trial_result(model_id, self.total_parameters[model_id], result) | |
def choice(self, candidates, mutator, model, index): | |
chosen = self.cur_sample[str(self.index)] | |
self.index += 1 | |
return chosen | |
class TPEStrategy(BaseStrategy): | |
""" | |
The Tree-structured Parzen Estimator (TPE) [bergstrahpo]_ is a sequential model-based optimization (SMBO) approach. | |
SMBO methods sequentially construct models to approximate the performance of hyperparameters based on historical measurements, | |
and then subsequently choose new hyperparameters to test based on this model. | |
References | |
---------- | |
.. [bergstrahpo] Bergstra et al., "Algorithms for Hyper-Parameter Optimization". | |
https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf | |
""" | |
def __init__(self): | |
self.tpe_sampler = TPESampler() | |
self.model_id = 0 | |
self.running_models = {} | |
def run(self, base_model, applied_mutators): | |
sample_space = [] | |
new_model = base_model | |
for mutator in applied_mutators: | |
recorded_candidates, new_model = mutator.dry_run(new_model) | |
sample_space.extend(recorded_candidates) | |
self.tpe_sampler.update_sample_space(sample_space) | |
_logger.info('TPE strategy has been started.') | |
while not budget_exhausted(): | |
avail_resource = query_available_resources() | |
if avail_resource > 0: | |
model = base_model | |
_logger.debug('New model created. Applied mutators: %s', str(applied_mutators)) | |
self.tpe_sampler.generate_samples(self.model_id) | |
for mutator in applied_mutators: | |
mutator.bind_sampler(self.tpe_sampler) | |
model = mutator.apply(model) | |
# run models | |
submit_models(model) | |
self.running_models[self.model_id] = model | |
self.model_id += 1 | |
else: | |
time.sleep(2) | |
_logger.debug('num of running models: %d', len(self.running_models)) | |
to_be_deleted = [] | |
for _id, _model in self.running_models.items(): | |
if is_stopped_exec(_model): | |
if _model.metric is not None: | |
self.tpe_sampler.receive_result(_id, _model.metric) | |
_logger.debug('tpe receive results: %d, %s', _id, _model.metric) | |
to_be_deleted.append(_id) | |
for _id in to_be_deleted: | |
del self.running_models[_id] | |