class_docstr: GP tuner is a Bayesian Optimization method where Gaussian Process
  is used for modeling loss functions.
  
  Bayesian optimization works by constructing a posterior distribution of functions
  (a Gaussian Process) that best describes the function you want to optimize.
  As the number of observations grows, the posterior distribution improves,
  and the algorithm becomes more certain of which regions in parameter space
  are worth exploring and which are not.
  
  GP tuner is designed to minimize/maximize the number of steps required to find
  a combination of parameters that are close to the optimal combination.
  To do so, this method uses a proxy optimization problem (finding the maximum of
  the acquisition function) that, albeit still a hard problem, is cheaper
  (in the computational sense) to solve, and it's amenable to common tools.
  Therefore, Bayesian Optimization is suggested for situations where sampling the function
  to be optimized is very expensive.
  
  Note that the only acceptable types in the :doc:`search space </hpo/search_space>` are
  ``randint``, ``uniform``, ``quniform``, ``loguniform``, ``qloguniform``, and numerical ``choice``.
  
  This optimization approach is described in Section 3 of the paper
  `Algorithms for Hyper-Parameter Optimization <https://papers.nips.cc/paper/4443-algorithms-for-hyper-parameter-optimization.pdf>`__
  ( :footcite:t:`bergstra2011algorithms` ).
  
  Examples
  --------
  
  .. code-block::
  
      config.tuner.name = 'GP'
      config.tuner.class_args = {
          'optimize_mode': 'maximize',
          'utility': 'ei',
          'kappa': 5.0,
          'xi': 0.0,
          'nu': 2.5,
          'alpha': 1e-6,
          'cold_start_num': 10,
          'selection_num_warm_up': 100000,
          'selection_num_starting_points': 250
      }
  
  Parameters
  ----------
  optimize_mode : str
      Optimize mode, 'maximize' or 'minimize', by default 'maximize'
  utility : str
      Utility function (also called 'acquisition funcition') to use,
      which can be 'ei', 'ucb' or 'poi'. By default 'ei'.
  kappa : float
      Value used by utility function 'ucb'. The bigger kappa is,
      the more the tuner will be exploratory. By default 5.
  xi : float
      Used by utility function 'ei' and 'poi'. The bigger xi is,
      the more the tuner will be exploratory. By default 0.
  nu : float
      Used to specify Matern kernel. The smaller nu,
      the less smooth the approximated function is. By default 2.5.
  alpha : float
      Used to specify Gaussian Process Regressor.
      Larger values correspond to increased noise level in the observations.
      By default 1e-6.
  cold_start_num : int
      Number of random exploration to perform before Gaussian Process.
      By default 10.
  selection_num_warm_up : int
      Number of random points to evaluate for getting the point which
      maximizes the acquisition function. By default 100000
  selection_num_starting_points : int
      Number of times to run L-BFGS-B from a random starting point after the warmup.
      By default 250.
code: def __init__(
      self,
      optimize_mode="maximize",
      utility="ei",
      kappa=5,
      xi=0,
      nu=2.5,
      alpha=1e-6,
      cold_start_num=10,
      selection_num_warm_up=100000,
      selection_num_starting_points=250,
  ):
      self._optimize_mode = OptimizeMode(optimize_mode)
  
      # utility function related
      self._utility = utility
      self._kappa = kappa
      self._xi = xi
  
      # target space
      self._space = None
  
      self._random_state = np.random.RandomState()
  
      # nu, alpha are GPR related params
      self._gp = GaussianProcessRegressor(
          kernel=Matern(nu=nu),
          alpha=alpha,
          normalize_y=True,
          n_restarts_optimizer=25,
          random_state=self._random_state,
      )
      # num of random evaluations before GPR
      self._cold_start_num = cold_start_num
  
      # params for acq_max
      self._selection_num_warm_up = selection_num_warm_up
      self._selection_num_starting_points = (
          selection_num_starting_points
      )
  
      # num of imported data
      self._supplement_data_num = 0
  
imports: import warnings
  import logging
  import numpy
  from schema import Schema, Optional
  from sklearn.gaussian_process.kernels import Matern
  from sklearn.gaussian_process import GaussianProcessRegressor
  from nni import ClassArgsValidator
  from nni.common.hpo_utils import validate_search_space
  from nni.tuner import Tuner
  from nni.utils import OptimizeMode, extract_scalar_reward
  from .target_space import TargetSpace
  from .util import UtilityFunction, acq_max
label_desc: Use image node_id 1 to create a new GPTuner object from inherited base classes: Tuner with example: obj = GPTuner(optimize_mode, utility, kappa, xi, nu, alpha, cold_start_num, selection_num_warm_up, selection_num_starting_points)