<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def gradients(ys, xs, grad_ys=None):
 """Compute gradients in dtf. Args: ys: a list of Tensors xs: a list of Tensors grad_ys: an optional list of Tensors Returns: grad_xs: a list of Tensors """

  graph = ys[0].graph
  if not grad_ys:
    grad_ys = [Constant(y.mesh, 1.0, y.shape, y.dtype).outputs[0] for y in ys]
  # figure out what Tensors are downstream of xs
  downstream = set(xs)
  for op in graph.operations:
    if op.has_gradient:
      if set(op.inputs) & downstream:
        downstream |= set(op.outputs)
  tensor_to_gradient = dict(zip(ys, grad_ys))
  for op in graph.operations[::-1]:
    grad_outputs = [tensor_to_gradient.get(out) for out in op.outputs]
    if op.has_gradient and any(grad_outputs) and (set(op.inputs) & downstream):
      with tf.variable_scope(op.name + "/gradients"):
        input_grads = op.gradient(grad_outputs)
        for inp, grad in zip(op.inputs, input_grads):
          if inp in downstream and grad is not None:
            if inp in tensor_to_gradient:
              tensor_to_gradient[inp] += grad
            else:
              tensor_to_gradient[inp] = grad
  return [tensor_to_gradient.get(x, None) for x in xs]