class_docstr: A stateless base class for Gaussian process models, that is, those of the
  form
  
  .. math::
     :nowrap:
  
     \begin{align}
         \theta        & \sim p(\theta) \\
         f             & \sim \mathcal{GP}(m(x), k(x, x'; \theta)) \\
         f_i           & = f(x_i) \\
         y_i \,|\, f_i & \sim p(y_i|f_i)
     \end{align}
  
  This class mostly adds functionality for predictions. To use it, inheriting
  classes must define a predict_f function, which computes the means and
  variances of the latent function.
  
  These predictions are then pushed through the likelihood to obtain means
  and variances of held out data, self.predict_y.
  
  The predictions can also be used to compute the (log) density of held-out
  data via self.predict_log_density.
  
  It is also possible to draw samples from the latent GPs using
  self.predict_f_samples.
  
  If you are new to GPflow, see our :doc:`../../../../getting_started` for examples on how to use
  a model.
  
  :param kernel: Covariance function. $k$ above.
  :param likelihood: The likelihood of $y_i$, given $f_i$.
  :param mean_function: Mean of $f$.
  :param num_latent_gps: The number of latent GPs - the output dimension of $f$.
docstr: Calculates the number of latent GPs required based on the data as well
  as the type of kernel and likelihood.
docstr_tok: ["Calculates","the","number","of","latent","GPs","required","based","on","the","data","as","well","as","the","type","of","kernel","and","likelihood","."]
code: def calc_num_latent_gps_from_data(
      data: RegressionData, kernel: Kernel, likelihood: Likelihood
  ) -> int:
      """
      Calculates the number of latent GPs required based on the data as well
      as the type of kernel and likelihood.
      """
      _, Y = data
      output_dim = Y.shape[-1]
      return GPModel.calc_num_latent_gps(kernel, likelihood, output_dim)
  
imports: import abc
  from typing import Any, Optional
  import tensorflow
  from check_shapes import check_shapes
  from ..base import InputData, MeanAndVariance, Module, RegressionData
  from ..conditionals.util import sample_mvn
  from ..kernels import Kernel, MultioutputKernel
  from ..likelihoods import Likelihood, SwitchedLikelihood
  from ..mean_functions import MeanFunction, Zero
  from ..utilities import assert_params_false, to_default_float
label_desc: Use image node_id 2 for calling the GPModel obj's underlying member method code with example usage: obj.calc_num_latent_gps_from_data(data, kernel, likelihood) and returns: GPModel