code: def build_score_rb_loss_and_gradients(inference, var_list):
      """Build loss function and gradients based on the score function
      estimator [@paisley2012variational] and Rao-Blackwellization
      [@ranganath2014black].
  
      Computed by sampling from :math:`q(z;\lambda)` and evaluating the
      expectation using Monte Carlo sampling and Rao-Blackwellization.
      """
      # Build tensors for loss and gradient calculations. There is one set
      # for each sample from the variational distribution.
      p_log_probs = [{}] * inference.n_samples
      q_log_probs = [{}] * inference.n_samples
      base_scope = tf.get_default_graph().unique_name("inference") + "/"
      for s in range(inference.n_samples):
          # Form dictionary in order to replace conditioning on prior or
          # observed variable with conditioning on a specific value.
          scope = base_scope + tf.get_default_graph().unique_name(
              "sample"
          )
          dict_swap = {}
          for x, qx in six.iteritems(inference.data):
              if isinstance(x, RandomVariable):
                  if isinstance(qx, RandomVariable):
                      qx_copy = copy(qx, scope=scope)
                      dict_swap[x] = qx_copy.value()
                  else:
                      dict_swap[x] = qx
  
          for z, qz in six.iteritems(inference.latent_vars):
              # Copy q(z) to obtain new set of posterior samples.
              qz_copy = copy(qz, scope=scope)
              dict_swap[z] = qz_copy.value()
              q_log_probs[s][qz] = tf.reduce_sum(
                  inference.scale.get(z, 1.0)
                  * qz_copy.log_prob(tf.stop_gradient(dict_swap[z]))
              )
  
          for z in six.iterkeys(inference.latent_vars):
              z_copy = copy(z, dict_swap, scope=scope)
              p_log_probs[s][z] = tf.reduce_sum(
                  inference.scale.get(z, 1.0)
                  * z_copy.log_prob(dict_swap[z])
              )
  
          for x in six.iterkeys(inference.data):
              if isinstance(x, RandomVariable):
                  x_copy = copy(x, dict_swap, scope=scope)
                  p_log_probs[s][x] = tf.reduce_sum(
                      inference.scale.get(x, 1.0)
                      * x_copy.log_prob(dict_swap[x])
                  )
  
      # Take gradients of Rao-Blackwellized loss for each variational parameter.
      p_rvs = list(six.iterkeys(inference.latent_vars)) + [
          x
          for x in six.iterkeys(inference.data)
          if isinstance(x, RandomVariable)
      ]
      q_rvs = list(six.itervalues(inference.latent_vars))
      reverse_latent_vars = {
          v: k for k, v in six.iteritems(inference.latent_vars)
      }
      grads = []
      grads_vars = []
      for var in var_list:
          # Get all variational factors depending on the parameter.
          descendants = get_descendants(
              tf.convert_to_tensor(var), q_rvs
          )
          if len(descendants) == 0:
              continue  # skip if not a variational parameter
          # Get p and q's Markov blanket wrt these latent variables.
          var_p_rvs = set()
          for qz in descendants:
              z = reverse_latent_vars[qz]
              var_p_rvs.update(z.get_blanket(p_rvs) + [z])
  
          var_q_rvs = set()
          for qz in descendants:
              var_q_rvs.update(qz.get_blanket(q_rvs) + [qz])
  
          pi_log_prob = [0.0] * inference.n_samples
          qi_log_prob = [0.0] * inference.n_samples
          for s in range(inference.n_samples):
              pi_log_prob[s] = tf.reduce_sum(
                  [p_log_probs[s][rv] for rv in var_p_rvs]
              )
              qi_log_prob[s] = tf.reduce_sum(
                  [q_log_probs[s][rv] for rv in var_q_rvs]
              )
  
          pi_log_prob = tf.stack(pi_log_prob)
          qi_log_prob = tf.stack(qi_log_prob)
          grad = tf.gradients(
              -tf.reduce_mean(
                  qi_log_prob
                  * tf.stop_gradient(pi_log_prob - qi_log_prob)
              )
              + tf.reduce_sum(tf.losses.get_regularization_losses()),
              var,
          )
          grads.extend(grad)
          grads_vars.append(var)
  
      # Take gradients of total loss function for model parameters.
      loss = -(
          tf.reduce_mean(
              [
                  tf.reduce_sum(list(six.itervalues(p_log_prob)))
                  for p_log_prob in p_log_probs
              ]
          )
          - tf.reduce_mean(
              [
                  tf.reduce_sum(list(six.itervalues(q_log_prob)))
                  for q_log_prob in q_log_probs
              ]
          )
          - tf.reduce_sum(tf.losses.get_regularization_losses())
      )
      model_vars = [v for v in var_list if v not in grads_vars]
      model_grads = tf.gradients(loss, model_vars)
      grads.extend(model_grads)
      grads_vars.extend(model_vars)
      grads_and_vars = list(zip(grads, grads_vars))
      return loss, grads_and_vars
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import six
  import tensorflow
  from edward.inferences.variational_inference import VariationalInference
  from edward.models import RandomVariable
  from edward.util import copy, get_descendants
label_desc: Use image node_id 7 for calling a global function with example usage: build_score_rb_loss_and_gradients(inference, var_list) and returns: loss,  grads_and_vars