class_docstr: A model for high-dimensional output regression.
  
  As described in [Zhe2019hogp]_. “Higher-order” means that the predictions
  are matrices (tensors) with at least two dimensions, such as images or
  grids of images, or measurements taken from a region of at least two
  dimensions.
  The posterior uses Matheron's rule [Doucet2010sampl]_
  as described in [Maddox2021bohdo]_.
  
  `HigherOrderGP` differs from a "vector” multi-output model in that it uses
  Kronecker algebra to obtain parsimonious covariance matrices for these
  outputs (see `KroneckerMultiTaskGP` for more information). For example,
  imagine a 10 x 20 x 30 grid of images. If we were to vectorize the
  resulting 6,000 data points in order to use them in a non-higher-order GP,
  they would have a 6,000 x 6,000 covariance matrix, with 36 million entries.
  The Kronecker structure allows representing this as a product of 10x10,
  20x20, and 30x30 covariance matrices, with only 1,400 entries.
  
  NOTE: This model requires the use of specialized Kronecker solves in
  linear operator, which are disabled by default in BoTorch. These are enabled
  by default in the `HigherOrderGP.posterior` call. However, they need to be
  manually enabled by the user during model fitting.
  
  Example:
      >>> from linear_operator.settings import _fast_solves
      >>> model = SingleTaskGP(train_X, train_Y)
      >>> mll = ExactMarginalLogLikelihood(model.likelihood, model)
      >>> with _fast_solves(True):
      >>>     fit_gpytorch_mll_torch(mll)
      >>> samples = model.posterior(test_X).rsample()
docstr: Args:
      train_X: A `batch_shape x n x d`-dim tensor of training inputs.
      train_Y: A `batch_shape x n x output_shape`-dim tensor of training targets.
      likelihood: Gaussian likelihood for the model.
      covar_modules: List of kernels for each output structure.
      num_latent_dims: Sizes for the latent dimensions.
      learn_latent_pars: If true, learn the latent parameters.
      latent_init: [default or gp] how to initialize the latent parameters.
docstr_tok: ["Args",":","train_X",":","A","`","batch_shape","x","n","x","d","`","-dim","tensor","of","training","inputs",".","train_Y",":","A","`","batch_shape","x","n","x","output_shape","`","-dim","tensor","of","training","targets",".","likelihood",":","Gaussian","likelihood","for","the","model",".","covar_modules",":","List","of","kernels","for","each","output","structure",".","num_latent_dims",":","Sizes","for","the","latent","dimensions",".","learn_latent_pars",":","If","true",",","learn","the","latent","parameters",".","latent_init",":","[","default","or","gp","]","how","to","initialize","the","latent","parameters","."]
code: def __init__(
      self,
      train_X: Tensor,
      train_Y: Tensor,
      likelihood: Optional[Likelihood] = None,
      covar_modules: Optional[List[Kernel]] = None,
      num_latent_dims: Optional[List[int]] = None,
      learn_latent_pars: bool = True,
      latent_init: str = "default",
      outcome_transform: Optional[OutcomeTransform] = None,
      input_transform: Optional[InputTransform] = None,
  ):
      r"""
      Args:
          train_X: A `batch_shape x n x d`-dim tensor of training inputs.
          train_Y: A `batch_shape x n x output_shape`-dim tensor of training targets.
          likelihood: Gaussian likelihood for the model.
          covar_modules: List of kernels for each output structure.
          num_latent_dims: Sizes for the latent dimensions.
          learn_latent_pars: If true, learn the latent parameters.
          latent_init: [default or gp] how to initialize the latent parameters.
      """
  
      if input_transform is not None:
          input_transform.to(train_X)
  
      # infer the dimension of `output_shape`.
      num_output_dims = train_Y.dim() - train_X.dim() + 1
      batch_shape = train_X.shape[:-2]
      if len(batch_shape) > 1:
          raise NotImplementedError(
              "HigherOrderGP currently only supports 1-dim `batch_shape`."
          )
  
      if outcome_transform is not None:
          if isinstance(
              outcome_transform, Standardize
          ) and not isinstance(outcome_transform, FlattenedStandardize):
              warnings.warn(
                  "HigherOrderGP does not support the outcome_transform "
                  "`Standardize`! Using `FlattenedStandardize` with `output_shape="
                  f"{train_Y.shape[- num_output_dims:]} and batch_shape="
                  f"{batch_shape} instead.",
                  RuntimeWarning,
              )
              outcome_transform = FlattenedStandardize(
                  output_shape=train_Y.shape[-num_output_dims:],
                  batch_shape=batch_shape,
              )
          train_Y, _ = outcome_transform(train_Y)
  
      self._aug_batch_shape = batch_shape
      self._num_dimensions = num_output_dims + 1
      self._num_outputs = train_Y.shape[0] if batch_shape else 1
      self.target_shape = train_Y.shape[-num_output_dims:]
      self._input_batch_shape = batch_shape
  
      if likelihood is None:
          likelihood = get_gaussian_likelihood_with_gamma_prior(
              batch_shape=self._aug_batch_shape
          )
      else:
          self._is_custom_likelihood = True
  
      super().__init__(
          train_X,
          train_Y.view(*self._aug_batch_shape, -1),
          likelihood=likelihood,
      )
  
      if covar_modules is not None:
          self.covar_modules = ModuleList(covar_modules)
      else:
          self.covar_modules = ModuleList(
              [
                  MaternKernel(
                      nu=2.5,
                      lengthscale_prior=GammaPrior(3.0, 6.0),
                      batch_shape=self._aug_batch_shape,
                      ard_num_dims=1 if dim > 0 else train_X.shape[-1],
                  )
                  for dim in range(self._num_dimensions)
              ]
          )
  
      if num_latent_dims is None:
          num_latent_dims = [1] * (self._num_dimensions - 1)
  
      self.to(train_X)
  
      self._initialize_latents(
          latent_init=latent_init,
          num_latent_dims=num_latent_dims,
          learn_latent_pars=learn_latent_pars,
          device=train_Y.device,
          dtype=train_Y.dtype,
      )
  
      if outcome_transform is not None:
          self.outcome_transform = outcome_transform
      if input_transform is not None:
          self.input_transform = input_transform
  
imports: from __future__ import annotations
  import warnings
  from contextlib import ExitStack
  from typing import Any, List, Optional, Tuple, Union
  import torch
  from botorch.acquisition.objective import PosteriorTransform
  from botorch.models.gpytorch import BatchedMultiOutputGPyTorchModel
  from botorch.models.model import FantasizeMixin
  from botorch.models.transforms.input import InputTransform
  from botorch.models.transforms.outcome import OutcomeTransform, Standardize
  from botorch.models.utils import gpt_posterior_settings
  from botorch.models.utils.gpytorch_modules import get_gaussian_likelihood_with_gamma_prior
  from botorch.posteriors import GPyTorchPosterior, HigherOrderGPPosterior, TransformedPosterior
  from gpytorch.distributions import MultivariateNormal
  from gpytorch.kernels import Kernel, MaternKernel
  from gpytorch.likelihoods import Likelihood
  from gpytorch.models import ExactGP
  from gpytorch.priors.torch_priors import GammaPrior, MultivariateNormalPrior
  from gpytorch.settings import fast_pred_var, skip_posterior_variances
  from linear_operator.operators import BatchRepeatLinearOperator, DiagLinearOperator, KroneckerProductLinearOperator, LinearOperator, ZeroLinearOperator
  from linear_operator.settings import _fast_solves
  from torch import Tensor
  from torch.nn import ModuleList, Parameter, ParameterList
label_desc: Use image node_id 1 to create a new HigherOrderGP object from inherited base classes: BatchedMultiOutputGPyTorchModel, ExactGP, FantasizeMixin with example: obj = HigherOrderGP(train_X, train_Y, likelihood, covar_modules, num_latent_dims, learn_latent_pars, latent_init, outcome_transform, input_transform)