Compute the gradients of outputs w.r.t variables.

    Parameters
    ----------
    outputs: list of NDArray
    out_grads: list of NDArray or None

def backward(outputs, out_grads=None, retain_graph=False):
    """Compute the gradients of outputs w.r.t variables.

    Parameters
    ----------
    outputs: list of NDArray
    out_grads: list of NDArray or None
    """
    assert isinstance(outputs, (list, tuple)), \
        "outputs must be a list or tuple of NDArrays"

    if out_grads is None:
        check_call(_LIB.MXAutogradBackward(
            len(outputs),
            c_handle_array(outputs),
            ctypes.c_void_p(0),
            ctypes.c_int(retain_graph)))
        return

    ograd_handles = []
    for arr in out_grads:
        if arr is not None:
            ograd_handles.append(arr.handle)
        else:
            ograd_handles.append(NDArrayHandle(0))
    assert len(ograd_handles) == len(outputs), \
        "outputs and out_grads must have the same length"

    check_call(_LIB.MXAutogradBackward(
        len(outputs),
        c_handle_array(outputs),
        c_array(NDArrayHandle, ograd_handles),
        ctypes.c_int(retain_graph)))