# -*- coding: utf-8 -*-
"""Classes for ``gp_hyper_opt`` endpoints.
Includes:
1. pretty and backend views
"""
from pyramid.view import view_config
from moe.optimal_learning.python.constant import OPTIMIZER_TYPE_AND_OBJECTIVE_TO_DEFAULT_PARAMETERS, ENDPOINT_TO_DEFAULT_OPTIMIZER_TYPE
from moe.optimal_learning.python.cpp_wrappers.log_likelihood import multistart_hyperparameter_optimization
from moe.optimal_learning.python.linkers import LOG_LIKELIHOOD_TYPES_TO_LOG_LIKELIHOOD_METHODS
from moe.optimal_learning.python.timing import timing_context
from moe.views.constant import GP_HYPER_OPT_ROUTE_NAME, GP_HYPER_OPT_PRETTY_ROUTE_NAME
from moe.views.gp_pretty_view import GpPrettyView
from moe.views.optimizable_gp_pretty_view import OptimizableGpPrettyView
from moe.views.pretty_view import PRETTY_RENDERER
from moe.views.schemas.rest.gp_hyper_opt import GpHyperOptRequest, GpHyperOptResponse
from moe.views.utils import _make_domain_from_params, _make_gp_from_params, _make_optimizer_parameters_from_params
MODEL_SELECTION_TIMING_LABEL = 'model selection time'
[docs]class GpHyperOptView(OptimizableGpPrettyView):
"""Views for gp_hyper_opt endpoints."""
_route_name = GP_HYPER_OPT_ROUTE_NAME
_pretty_route_name = GP_HYPER_OPT_PRETTY_ROUTE_NAME
request_schema = GpHyperOptRequest()
response_schema = GpHyperOptResponse()
_pretty_default_request = {
"gp_historical_info": GpPrettyView._pretty_default_gp_historical_info,
"domain_info": {"dim": 1},
"covariance_info": GpPrettyView._pretty_default_covariance_info,
"hyperparameter_domain_info": {
"dim": 2,
"domain_bounds": [
{
"min": 0.1,
"max": 2.0,
},
{
"min": 0.1,
"max": 2.0,
},
],
},
}
def _get_default_optimizer_type(self, params):
"""Get the optimizer type associated with this REST endpoint and requested ``log_likelihood_type``.
:param params: a (partially) deserialized REST request with everything except possibly
``params['optimizer_info']``
:type params: dict
:return: optimizer type to use, one of :const:`moe.optimal_learning.python.constant.OPTIMIZER_TYPES`
:rtype: str
"""
log_likelihood_type = params.get('log_likelihood_info')
return ENDPOINT_TO_DEFAULT_OPTIMIZER_TYPE[(self._route_name, log_likelihood_type)]
def _get_default_optimizer_params(self, params):
"""Get the default optimizer parameters associated with the desired ``optimizer_type``, REST endpoint, and ``log_likelihood_type``.
:param params: a (partially) deserialized REST request with everything except possibly
``params['optimizer_info']``
:type params: dict
:return: default multistart and optimizer parameters to use with this REST request
:rtype: :class:`moe.optimal_learning.python.constant.DefaultOptimizerInfoTuple`
"""
optimizer_type = params['optimizer_info']['optimizer_type']
log_likelihood_type = params.get('log_likelihood_info')
optimizer_parameters_lookup = (optimizer_type, self._route_name, log_likelihood_type)
return OPTIMIZER_TYPE_AND_OBJECTIVE_TO_DEFAULT_PARAMETERS[optimizer_parameters_lookup]
@view_config(route_name=_pretty_route_name, renderer=PRETTY_RENDERER)
[docs] def pretty_view(self):
"""A pretty, browser interactive view for the interface. Includes form request and response.
.. http:get:: /gp/hyper_opt/pretty
"""
return self.pretty_response()
@view_config(route_name=_route_name, renderer='json', request_method='POST')
[docs] def gp_hyper_opt_view(self):
"""Endpoint for gp_hyper_opt POST requests.
.. http:post:: /gp/hyper_opt
Calculates the optimal hyperparameters for a gaussian process, given historical data.
:input: :class:`moe.views.schemas.rest.gp_hyper_opt.GpHyperOptRequest`
:output: :class:`moe.views.schemas.rest.gp_hyper_opt.GpHyperOptResponse`
:status 200: returns a response
:status 500: server error
"""
params = self.get_params_from_request()
max_num_threads = params.get('max_num_threads')
hyperparameter_domain = _make_domain_from_params(params, domain_info_key='hyperparameter_domain_info')
gaussian_process = _make_gp_from_params(params)
covariance_of_process, historical_data = gaussian_process.get_core_data_copy()
optimizer_class, optimizer_parameters, num_random_samples = _make_optimizer_parameters_from_params(params)
log_likelihood_type = params.get('log_likelihood_info')
log_likelihood_eval = LOG_LIKELIHOOD_TYPES_TO_LOG_LIKELIHOOD_METHODS[log_likelihood_type].log_likelihood_class(
covariance_of_process,
historical_data,
)
log_likelihood_optimizer = optimizer_class(
hyperparameter_domain,
log_likelihood_eval,
optimizer_parameters,
num_random_samples=num_random_samples,
)
hyperopt_status = {}
with timing_context(MODEL_SELECTION_TIMING_LABEL):
optimized_hyperparameters = multistart_hyperparameter_optimization(
log_likelihood_optimizer,
optimizer_parameters.num_multistarts,
max_num_threads=max_num_threads,
status=hyperopt_status,
)
covariance_of_process.hyperparameters = optimized_hyperparameters
log_likelihood_eval.current_point = optimized_hyperparameters
return self.form_response({
'endpoint': self._route_name,
'covariance_info': covariance_of_process.get_json_serializable_info(),
'status': {
'log_likelihood': log_likelihood_eval.compute_log_likelihood(),
'grad_log_likelihood': log_likelihood_eval.compute_grad_log_likelihood().tolist(),
'optimizer_success': hyperopt_status,
},
})