code: def opt_eig_ape_loss(
      design,
      loss_fn,
      num_samples,
      num_steps,
      optim,
      return_history=False,
      final_design=None,
      final_num_samples=None,
  ):
      if final_design is None:
          final_design = design
      if final_num_samples is None:
          final_num_samples = num_samples
  
      params = None
      history = []
      for step in range(num_steps):
          if params is not None:
              pyro.infer.util.zero_grads(params)
          with poutine.trace(param_only=True) as param_capture:
              agg_loss, loss = loss_fn(
                  design, num_samples, evaluation=return_history
              )
          params = set(
              site["value"].unconstrained()
              for site in param_capture.trace.nodes.values()
          )
          if torch.isnan(agg_loss):
              raise ArithmeticError(
                  "Encountered NaN loss in opt_eig_ape_loss"
              )
          agg_loss.backward(retain_graph=True)
          if return_history:
              history.append(loss)
          optim(params)
          try:
              optim.step()
          except AttributeError:
              pass
  
      _, loss = loss_fn(
          final_design, final_num_samples, evaluation=True
      )
      if return_history:
          return torch.stack(history), loss
      else:
          return loss
  
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 14 for calling a global function with example usage: opt_eig_ape_loss(design, loss_fn, num_samples, num_steps, optim, return_history, final_design, final_num_samples) and returns: torch,  loss, loss