171 lines
5.0 KiB
Python
171 lines
5.0 KiB
Python
#
|
|
# OtterTune - analysis/gpr_models.py
|
|
#
|
|
# Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
|
#
|
|
# Author: Dana Van Aken
|
|
|
|
import copy
|
|
import json
|
|
import os
|
|
|
|
import gpflow
|
|
import numpy as np
|
|
import tensorflow as tf
|
|
|
|
from .gprc import GPRC
|
|
|
|
|
|
class BaseModel(object):
|
|
|
|
# Min/max bounds for the kernel lengthscales
|
|
_LENGTHSCALE_BOUNDS = (0.1, 10.)
|
|
|
|
# Keys for each kernel's hyperparameters
|
|
_KERNEL_HP_KEYS = []
|
|
|
|
# The key for the likelihood parameter
|
|
_LIKELIHOOD_HP_KEY = 'GPRC/likelihood/variance'
|
|
|
|
def __init__(self, X, y, hyperparameters=None, optimize_hyperparameters=False,
|
|
learning_rate=0.001, maxiter=5000, **kwargs):
|
|
# Store model kwargs
|
|
self._model_kwargs = {
|
|
'hyperparameters': hyperparameters,
|
|
'optimize_hyperparameters': optimize_hyperparameters,
|
|
'learning_rate': learning_rate,
|
|
'maxiter': maxiter,
|
|
}
|
|
|
|
# Store kernel kwargs
|
|
kernel_kwargs = self._get_kernel_kwargs(X_dim=X.shape[1], **kwargs)
|
|
if hyperparameters is not None:
|
|
self._assign_kernel_hyperparams(hyperparameters, kernel_kwargs)
|
|
self._kernel_kwargs = copy.deepcopy(kernel_kwargs)
|
|
|
|
# Build the kernels and the model
|
|
with gpflow.defer_build():
|
|
k = self._build_kernel(kernel_kwargs, optimize_hyperparameters=optimize_hyperparameters, **kwargs)
|
|
m = GPRC(X, y, kern=k)
|
|
if hyperparameters is not None and self._LIKELIHOOD_HP_KEY in hyperparameters:
|
|
m.likelihood.variance = hyperparameters[self._LIKELIHOOD_HP_KEY]
|
|
m.compile()
|
|
|
|
# If enabled, optimize the hyperparameters
|
|
if optimize_hyperparameters:
|
|
opt = gpflow.train.AdamOptimizer(learning_rate)
|
|
opt.minimize(m, maxiter=maxiter)
|
|
self.model = m
|
|
|
|
def _get_kernel_kwargs(self, **kwargs):
|
|
return []
|
|
|
|
def _build_kernel(self, kernel_kwargs, **kwargs):
|
|
return None
|
|
|
|
def get_hyperparameters(self):
|
|
return {k: float(v) if v.ndim == 0 else v.tolist()
|
|
for k, v in self.model.read_values().items()}
|
|
|
|
def get_model_parameters(self):
|
|
return {
|
|
'model_params': copy.deepcopy(self._model_kwargs),
|
|
'kernel_params': copy.deepcopy(self._kernel_kwargs)
|
|
}
|
|
|
|
def _assign_kernel_hyperparams(self, hyperparams, kernel_kwargs):
|
|
for i, kernel_keys in enumerate(self._KERNEL_HP_KEYS):
|
|
for key in kernel_keys:
|
|
if key in hyperparams:
|
|
argname = key.rsplit('/', 1)[-1]
|
|
kernel_kwargs[i][argname] = hyperparams[key]
|
|
|
|
@staticmethod
|
|
def load_hyperparameters(path, hp_idx=0):
|
|
with open(path, 'r') as f:
|
|
hyperparams = json.load(f)['hyperparameters']
|
|
if isinstance(hyperparams, list):
|
|
assert hp_idx >= 0, 'hp_idx: {} (expected >= 0)'.format(hp_idx)
|
|
if hp_idx >= len(hyperparams):
|
|
hp_idx = -1
|
|
hyperparams = hyperparams[hp_idx]
|
|
return hyperparams
|
|
|
|
|
|
class BasicGP(BaseModel):
|
|
|
|
_KERNEL_HP_KEYS = [
|
|
[
|
|
'GPRC/kern/kernels/0/variance',
|
|
'GPRC/kern/kernels/0/lengthscales',
|
|
]
|
|
]
|
|
|
|
def _get_kernel_kwargs(self, **kwargs):
|
|
X_dim = kwargs.pop('X_dim')
|
|
return [
|
|
{
|
|
'input_dim': X_dim,
|
|
'ARD': False
|
|
}
|
|
]
|
|
|
|
def _build_kernel(self, kernel_kwargs, **kwargs):
|
|
k = gpflow.kernels.Matern12(lengthscales=2, **kernel_kwargs[0])
|
|
if kwargs.pop('optimize_hyperparameters'):
|
|
k.lengthscales.transform = gpflow.transforms.Logistic(
|
|
*self._LENGTHSCALE_BOUNDS)
|
|
return k
|
|
|
|
|
|
class ExpWhiteGP(BaseModel):
|
|
|
|
_KERNEL_HP_KEYS = [
|
|
[
|
|
'GPRC/kern/kernels/0/variance',
|
|
'GPRC/kern/kernels/0/lengthscales',
|
|
],
|
|
[
|
|
'GPRC/kern/kernels/1/variance',
|
|
],
|
|
]
|
|
|
|
def _get_kernel_kwargs(self, **kwargs):
|
|
X_dim = kwargs.pop('X_dim')
|
|
return [
|
|
{
|
|
'input_dim': X_dim,
|
|
'ARD': False
|
|
},
|
|
{
|
|
'input_dim': X_dim,
|
|
},
|
|
]
|
|
|
|
def _build_kernel(self, kernel_kwargs, **kwargs):
|
|
k0 = gpflow.kernels.Exponential(**kernel_kwargs[0])
|
|
k1 = gpflow.kernels.White(**kernel_kwargs[1])
|
|
if kwargs.pop('optimize_hyperparameters'):
|
|
k0.lengthscales.transform = gpflow.transforms.Logistic(
|
|
*self._LENGTHSCALE_BOUNDS)
|
|
k = k0 + k1
|
|
return k
|
|
|
|
|
|
_MODEL_MAP = {
|
|
'BasicGP': BasicGP,
|
|
'ExpWhiteGP': ExpWhiteGP,
|
|
}
|
|
|
|
|
|
def create_model(model_name, **kwargs):
|
|
# Update tensorflow session settings to enable GPU sharing
|
|
gpflow.settings.session.update(gpu_options=tf.GPUOptions(allow_growth=True))
|
|
check_valid(model_name)
|
|
return _MODEL_MAP[model_name](**kwargs)
|
|
|
|
|
|
def check_valid(model_name):
|
|
if model_name not in _MODEL_MAP:
|
|
raise ValueError('Invalid GPR model name: {}'.format(model_name))
|