def value_and_gradient(f, xs, use_gradient_tape=False, name=None):
with tf.compat.v1.name_scope(name, '<STR_LIT>', [xs]):<EOL><INDENT>is_xs_list_like = isinstance(xs, (tuple, list))<EOL>if not is_xs_list_like:<EOL><INDENT>xs = [xs]<EOL><DEDENT>xs = [tf.convert_to_tensor(value=x, name='<STR_LIT>'.format(i))<EOL>for i, x in enumerate(xs)]<EOL>if tf.executing_eagerly() or use_gradient_tape:<EOL><INDENT>with tf.GradientTape(watch_accessed_variables=False) as tape:<EOL><INDENT>for x in xs:<EOL><INDENT>tape.watch(x)<EOL><DEDENT>y = f(*xs)<EOL><DEDENT>dydx = tape.gradient(y, xs)<EOL><DEDENT>else:<EOL><INDENT>y = f(*xs)<EOL>dydx = tf.gradients(ys=y, xs=xs)<EOL><DEDENT>if not is_xs_list_like:<EOL><INDENT>dydx = dydx[<NUM_LIT:0>]<EOL><DEDENT>return y, dydx<EOL><DEDENT>
Computes `f(*xs)` and its gradients wrt to `*xs`.

    Args:
      f: Python `callable` to be differentiated. If `f` returns a scalar, this
        scalar will be differentiated. If `f` returns a tensor or list of tensors,
        by default a scalar will be computed by adding all their values to produce
        a single scalar. If desired, the tensors can be elementwise multiplied by
        the tensors passed as the `dy` keyword argument to the returned gradient
        function.
      xs: Python list of parameters of f for which to differentiate. (Can also
        be single `Tensor`.)
      use_gradient_tape: Python `bool` indicating that `tf.GradientTape`
        should be used regardless of `tf.executing_eagerly()` status.
        Default value: `False`.
      name: Python `str` name prefixed to ops created by this function.
        Default value: `None` (i.e., `'value_and_gradient'`).

    Returns:
      y: `y = f(*xs)`.
      dydx: Gradient of `y` wrt each of `xs`.