code: def build_mog_bbsvi(
      logprob, num_samples, k=10, rs=npr.RandomState(0)
  ):
      init_component_var_params = init_gaussian_var_params
      component_log_density = variational_log_density_gaussian
      component_sample = sample_diag_gaussian
  
      def unpack_mixture_params(mixture_params):
          log_weights = log_normalize(mixture_params[:k])
          var_params = np.reshape(mixture_params[k:], (k, -1))
          return log_weights, var_params
  
      def init_var_params(D, rs=npr.RandomState(0), **kwargs):
          log_weights = np.ones(k)
          component_weights = [
              init_component_var_params(D, rs=rs, **kwargs)
              for i in range(k)
          ]
          return np.concatenate([log_weights] + component_weights)
  
      def sample(var_mixture_params, num_samples, rs):
          """Sample locations aren't a continuous function of parameters
          due to multinomial sampling."""
          log_weights, var_params = unpack_mixture_params(
              var_mixture_params
          )
          samples = np.concatenate(
              [
                  component_sample(params_k, num_samples, rs)[
                      :, np.newaxis, :
                  ]
                  for params_k in var_params
              ],
              axis=1,
          )
          ixs = np.random.choice(
              k, size=num_samples, p=np.exp(log_weights)
          )
          return np.array(
              [samples[i, ix, :] for i, ix in enumerate(ixs)]
          )
  
      def mixture_log_density(var_mixture_params, x):
          """Returns a weighted average over component densities."""
          log_weights, var_params = unpack_mixture_params(
              var_mixture_params
          )
          component_log_densities = np.vstack(
              [
                  component_log_density(params_k, x)
                  for params_k in var_params
              ]
          ).T
          return logsumexp(
              component_log_densities + log_weights,
              axis=1,
              keepdims=False,
          )
  
      def mixture_elbo(var_mixture_params, t):
          # We need to only sample the continuous component parameters,
          # and integrate over the discrete component choice
  
          def mixture_lower_bound(params):
              """Provides a stochastic estimate of the variational lower bound."""
              samples = component_sample(params, num_samples, rs)
              log_qs = mixture_log_density(var_mixture_params, samples)
              log_ps = logprob(samples, t)
              log_ps = np.reshape(log_ps, (num_samples, -1))
              log_qs = np.reshape(log_qs, (num_samples, -1))
              return np.mean(log_ps - log_qs)
  
          log_weights, var_params = unpack_mixture_params(
              var_mixture_params
          )
          component_elbos = np.stack(
              [mixture_lower_bound(params_k) for params_k in var_params]
          )
          return np.sum(component_elbos * np.exp(log_weights))
  
      return init_var_params, mixture_elbo, mixture_log_density, sample
  
file_path: autograd/examples/mixture_variational_inference.py
imports: from __future__ import absolute_import
  from __future__ import print_function
  import matplotlib.pyplot
  import autograd.numpy
  import autograd.numpy.random
  import autograd.scipy.stats.norm
  from autograd.scipy.special import logsumexp
  from autograd import grad
  from autograd.misc.optimizers import adam
label_desc: Use image node_id 8 for calling a global function with example usage: build_mog_bbsvi(logprob, num_samples, k, rs) and returns: init_var_params,  mixture_elbo,  mixture_log_density,  sample, log_weights,  var_params, np, np, logsumexp, np, np