code: def _marginal_likelihood_loss(
      model,
      marginal_guide,
      likelihood_guide,
      observation_labels,
      target_labels,
  ):
      """Marginal_likelihood loss: to evaluate directly use `marginal_likelihood_eig` setting `num_steps=0`."""
  
      def loss_fn(design, num_particles, evaluation=False, **kwargs):
          expanded_design = lexpand(design, num_particles)
  
          # Sample from p(y | d)
          trace = poutine.trace(model).get_trace(expanded_design)
          y_dict = {
              l: trace.nodes[l]["value"] for l in observation_labels
          }
          theta_dict = {
              l: trace.nodes[l]["value"] for l in target_labels
          }
  
          # Run through q(y | d)
          qyd = pyro.condition(marginal_guide, data=y_dict)
          marginal_trace = poutine.trace(qyd).get_trace(
              expanded_design, observation_labels, target_labels
          )
          marginal_trace.compute_log_prob()
  
          # Run through q(y | theta, d)
          qythetad = pyro.condition(likelihood_guide, data=y_dict)
          cond_trace = poutine.trace(qythetad).get_trace(
              theta_dict,
              expanded_design,
              observation_labels,
              target_labels,
          )
          cond_trace.compute_log_prob()
          terms = -sum(
              marginal_trace.nodes[l]["log_prob"]
              for l in observation_labels
          )
  
          # At evaluation time, use the right estimator, q(y | theta, d) - q(y | d)
          # At training time, use -q(y | theta, d) - q(y | d) so gradients go the same way
          if evaluation:
              terms += sum(
                  cond_trace.nodes[l]["log_prob"]
                  for l in observation_labels
              )
          else:
              terms -= sum(
                  cond_trace.nodes[l]["log_prob"]
                  for l in observation_labels
              )
  
          return _safe_mean_terms(terms)
  
      return loss_fn
  
imports: import math
  import warnings
  import torch
  import pyro
  from pyro import poutine
  from pyro.contrib.oed.search import Search
  from pyro.contrib.util import lexpand
  from pyro.infer import SVI, EmpiricalMarginal, Importance
  from pyro.infer.autoguide.utils import mean_field_entropy
  from pyro.util import torch_isinf, torch_isnan
label_desc: Use image node_id 19 for calling a global function with example usage: _marginal_likelihood_loss(model, marginal_guide, likelihood_guide, observation_labels, target_labels) and returns: loss_fn, _safe_mean_terms