class_docstr: Compiled Sequential Importance Sampling, allowing compilation of a guide
  program to minimise KL(model posterior || guide), and inference with
  importance sampling.
  
  **Reference**
  "Inference Compilation and Universal Probabilistic Programming" `pdf https://arxiv.org/pdf/1610.09900.pdf`
  
  :param model: probabilistic model defined as a function. Must accept a
      keyword argument named `observations`, in which observed values are
      passed as, with the names of nodes as the keys.
  :param guide: guide function which is used as an approximate posterior. Must
      also accept `observations` as keyword argument.
  :param optim: a Pyro optimizer
  :type optim: pyro.optim.PyroOptim
  :param num_inference_samples: The number of importance-weighted samples to
      draw during inference.
  :param training_batch_size: Number of samples to use to approximate the loss
      before each gradient descent step during training.
  :param validation_batch_size: Number of samples to use for calculating
      validation loss (will only be used if `.validation_loss` is called).
class_docstr_tok: ["Compiled","Sequential","Importance","Sampling",",","allowing","compilation","of","a","guide","program","to","minimise","KL","(","model","posterior","||","guide",")",",","and","inference","with","importance","sampling",".","*","*","Reference","*","*","''","Inference","Compilation","and","Universal","Probabilistic","Programming","''","`","pdf","https",":","\/\/arxiv.org\/pdf\/1610.09900.pdf","`",":","param","model",":","probabilistic","model","defined","as","a","function",".","Must","accept","a","keyword","argument","named","`","observations","`",",","in","which","observed","values","are","passed","as",",","with","the","names","of","nodes","as","the","keys",".",":","param","guide",":","guide","function","which","is","used","as","an","approximate","posterior",".","Must","also","accept","`","observations","`","as","keyword","argument",".",":","param","optim",":","a","Pyro","optimizer",":","type","optim",":","pyro.optim.PyroOptim",":","param","num_inference_samples",":","The","number","of","importance-weighted","samples","to","draw","during","inference",".",":","param","training_batch_size",":","Number","of","samples","to","use","to","approximate","the","loss","before","each","gradient","descent","step","during","training",".",":","param","validation_batch_size",":","Number","of","samples","to","use","for","calculating","validation","loss","(","will","only","be","used","if","`",".validation_loss","`","is","called",")","."]
docstr: :returns: an estimate of the loss (expectation over p(x, y) of
      -log q(x, y) ) - where p is the model and q is the guide
  :rtype: float
  
  If a batch is provided, the loss is estimated using these traces
  Otherwise, a fresh batch is generated from the model.
  
  If grads is True, will also call `backward` on loss.
  
  `args` and `kwargs` are passed to the model and guide.
docstr_tok: [":","returns",":","an","estimate","of","the","loss","(","expectation","over","p","(","x",",","y",")","of","-log","q","(","x",",","y",")",")","-","where","p","is","the","model","and","q","is","the","guide",":","rtype",":","float","If","a","batch","is","provided",",","the","loss","is","estimated","using","these","traces","Otherwise",",","a","fresh","batch","is","generated","from","the","model",".","If","grads","is","True",",","will","also","call","`","backward","`","on","loss",".","`","args","`","and","`","kwargs","`","are","passed","to","the","model","and","guide","."]
code: def loss_and_grads(self, grads, batch, *args, **kwargs):
      """
      :returns: an estimate of the loss (expectation over p(x, y) of
          -log q(x, y) ) - where p is the model and q is the guide
      :rtype: float
  
      If a batch is provided, the loss is estimated using these traces
      Otherwise, a fresh batch is generated from the model.
  
      If grads is True, will also call `backward` on loss.
  
      `args` and `kwargs` are passed to the model and guide.
      """
      if batch is None:
          batch = (
              self._sample_from_joint(*args, **kwargs)
              for _ in range(self.training_batch_size)
          )
          batch_size = self.training_batch_size
      else:
          batch_size = len(batch)
  
      loss = 0
      for model_trace in batch:
          with poutine.trace(param_only=True) as particle_param_capture:
              guide_trace = self._get_matched_trace(
                  model_trace, *args, **kwargs
              )
          particle_loss = self._differentiable_loss_particle(
              guide_trace
          )
          particle_loss /= batch_size
  
          if grads:
              guide_params = set(
                  site["value"].unconstrained()
                  for site in particle_param_capture.trace.nodes.values()
              )
              guide_grads = torch.autograd.grad(
                  particle_loss, guide_params, allow_unused=True
              )
              for guide_grad, guide_param in zip(
                  guide_grads, guide_params
              ):
                  if guide_grad is None:
                      continue
                  guide_param.grad = (
                      guide_grad
                      if guide_param.grad is None
                      else guide_param.grad + guide_grad
                  )
  
          loss += torch_item(particle_loss)
  
      warn_if_nan(loss, "loss")
      return loss
  
file_path: pyro/pyro/infer/csis.py
imports: import itertools
  import torch
  import pyro
  import pyro.poutine
  from pyro.infer.importance import Importance
  from pyro.infer.util import torch_item
  from pyro.poutine.util import prune_subsample_sites
  from pyro.util import check_model_guide_match, warn_if_nan
label_desc: Use image node_id 4 for calling the CSIS obj's underlying member method code with example usage: obj.loss_and_grads(grads, batch) and returns: loss