text: op {
    graph_op_name: "SymbolicGradient"
    in_arg {
      name: "input"
      description: <<END
  a list of input tensors of size N + M;
  END
    }
    out_arg {
      name: "output"
      description: <<END
  a list of output tensors of size N;
  END
    }
    attr {
      name: "Tin"
      description: <<END
  the type list for the input list.
  END
    }
    attr {
      name: "Tout"
      description: <<END
  the type list for the input list.
  END
    }
    attr {
      name: "f"
      description: <<END
  The function we want to compute the gradient for.
  
  The function 'f' must be a numerical function which takes N inputs and
  produces M outputs. Its gradient function 'g', which is computed by
  this SymbolicGradient op is a function taking N + M inputs and
  produces N outputs.
  
  I.e. if we have
     (y1, y2, ..., y_M) = f(x1, x2, ..., x_N),
  then, g is
     (dL/dx1, dL/dx2, ..., dL/dx_N) = g(x1, x2, ..., x_N,
                                       dL/dy1, dL/dy2, ..., dL/dy_M),
  
  where L is a scalar-value function of (x1, x2, ..., xN) (e.g., the
  loss function). dL/dx_i is the partial derivative of L with respect
  to x_i.
  
  (Needs some math expert to say the comment above better.)
  END
    }
    summary: "Computes the gradient function for function f via backpropagation."
  }
  