code: def make_val_and_grad(lossfn, train_vars):
      """
      Makes a function that ouptuts the loss and gradient in a format compatible
      with scipy.optimize.minimize
      """
  
      def val_and_grad(theta):
          with tf.GradientTape() as tape:
              tape.watch(train_vars)
              unpacked_theta = unpack_trainable_vars(theta, train_vars)
              for var, val in zip(train_vars, unpacked_theta):
                  var.assign(val)
              loss = lossfn(theta)
          grad = tape.gradient(loss, train_vars)
          packed_grad = pack_trainable_vars(grad)
          return loss.numpy(), packed_grad.numpy()
  
      return val_and_grad
  
file_path: brainiak/brainiak/matnormal/utils.py
imports: import tensorflow
  import tensorflow_probability
  from scipy.stats import norm
  from numpy.linalg import cholesky
  import numpy
label_desc: Use image node_id 9 for calling a global function with example usage: make_val_and_grad(lossfn, train_vars) and returns: val_and_grad, loss,  packed_grad