code: def model_list_to_batched(
      model_list: ModelListGP,
  ) -> BatchedMultiOutputGPyTorchModel:
      """Convert a ModelListGP to a BatchedMultiOutputGPyTorchModel.
  
      Args:
          model_list: The `ModelListGP` to be converted to the appropriate
              `BatchedMultiOutputGPyTorchModel`. All sub-models must be of the same
              type and have the shape (batch shape and number of training inputs).
  
      Returns:
          The model converted into a `BatchedMultiOutputGPyTorchModel`.
  
      Example:
          >>> list_gp = ModelListGP(gp1, gp2)
          >>> batch_gp = model_list_to_batched(list_gp)
      """
      was_training = model_list.training
      model_list.train()
      models = model_list.models
      _check_compatibility(models)
  
      # if the list has only one model, we can just return a copy of that
      if len(models) == 1:
          return deepcopy(models[0])
  
      # construct inputs
      train_X = deepcopy(models[0].train_inputs[0])
      train_Y = torch.stack(
          [m.train_targets.clone() for m in models], dim=-1
      )
      kwargs = {"train_X": train_X, "train_Y": train_Y}
      if isinstance(models[0].likelihood, FixedNoiseGaussianLikelihood):
          kwargs["train_Yvar"] = torch.stack(
              [m.likelihood.noise_covar.noise.clone() for m in models],
              dim=-1,
          )
      if isinstance(models[0], SingleTaskMultiFidelityGP):
          init_args = models[0]._init_args
          if not all(
              v == m._init_args[k]
              for m in models[1:]
              for k, v in init_args.items()
          ):
              raise UnsupportedError(
                  "All models must have the same fidelity parameters."
              )
          kwargs.update(init_args)
  
      # add batched kernel, except if the model type is SingleTaskMultiFidelityGP,
      # which does not have a `covar_module`
      if not isinstance(models[0], SingleTaskMultiFidelityGP):
          batch_length = len(models)
          covar_module = _batched_kernel(
              models[0].covar_module, batch_length
          )
          kwargs["covar_module"] = covar_module
  
      # construct the batched GP model
      input_transform = getattr(models[0], "input_transform", None)
      batch_gp = models[0].__class__(
          input_transform=input_transform, **kwargs
      )
      (
          adjusted_batch_keys,
          non_adjusted_batch_keys,
      ) = _get_adjusted_batch_keys(
          batch_state_dict=batch_gp.state_dict(),
          input_transform=input_transform,
      )
      input_batch_dims = len(models[0]._input_batch_shape)
  
      # ensure scalars agree (TODO: Allow different priors for different outputs)
      for n in non_adjusted_batch_keys:
          v0 = _get_module(models[0], n)
          if not all(
              torch.equal(_get_module(m, n), v0) for m in models[1:]
          ):
              raise UnsupportedError(
                  "All scalars must have the same value."
              )
  
      # ensure dimensions of all tensors agree
      for n in adjusted_batch_keys:
          shape0 = _get_module(models[0], n).shape
          if not all(
              _get_module(m, n).shape == shape0 for m in models[1:]
          ):
              raise UnsupportedError(
                  "All tensors must have the same shape."
              )
  
      # now construct the batched state dict
      non_adjusted_batch_state_dict = {
          s: p.clone()
          for s, p in models[0].state_dict().items()
          if s in non_adjusted_batch_keys
      }
      adjusted_batch_state_dict = {
          t: (
              torch.stack(
                  [m.state_dict()[t].clone() for m in models],
                  dim=input_batch_dims,
              )
              if "active_dims" not in t
              else models[0].state_dict()[t].clone()
          )
          for t in adjusted_batch_keys
      }
      batch_state_dict = {
          **non_adjusted_batch_state_dict,
          **adjusted_batch_state_dict,
      }
  
      # load the state dict into the new model
      batch_gp.load_state_dict(batch_state_dict)
  
      return batch_gp.train(mode=was_training)
  
imports: from __future__ import annotations
  from copy import deepcopy
  from typing import Dict, Optional, Set, Tuple
  import torch
  from botorch.exceptions import UnsupportedError
  from botorch.models.gp_regression import HeteroskedasticSingleTaskGP
  from botorch.models.gp_regression_fidelity import SingleTaskMultiFidelityGP
  from botorch.models.gp_regression_mixed import MixedSingleTaskGP
  from botorch.models.gpytorch import BatchedMultiOutputGPyTorchModel
  from botorch.models.model_list_gp_regression import ModelListGP
  from botorch.models.transforms.input import InputTransform
  from botorch.models.transforms.outcome import OutcomeTransform
  from gpytorch.likelihoods.gaussian_likelihood import FixedNoiseGaussianLikelihood
  from torch import Tensor
  from torch.nn import Module
label_desc: Use image node_id 3 for calling a global function with example usage: model_list_to_batched(model_list) and returns: batch_gp, deepcopy