import six


def _Net_backward(self, diffs=None, start=None, end=None, **kwargs):
    """
    Backward pass: prepare diffs and run the net backward.

    Parameters
    ----------
    diffs : list of diffs to return in addition to bottom diffs.
    kwargs : Keys are output blob names and values are diff ndarrays.
            If None, top diffs are taken from forward loss.
    start : optional name of layer at which to begin the backward pass
    end : optional name of layer at which to finish the backward pass
        (inclusive)

    Returns
    -------
    outs: {blob name: diff ndarray} dict.
    """
    if diffs is None:
        diffs = []

    if start is not None:
        start_ind = list(self._layer_names).index(start)
    else:
        start_ind = len(self.layers) - 1

    if end is not None:
        end_ind = list(self._layer_names).index(end)
        outputs = set(self.bottom_names[end] + diffs)
    else:
        end_ind = 0
        outputs = set(self.inputs + diffs)

    if kwargs:
        if set(kwargs.keys()) != set(self.outputs):
            raise Exception('Top diff arguments do not match net outputs.')
        # Set top diffs according to defined shapes and make arrays single and
        # C-contiguous as Caffe expects.
        for top, diff in six.iteritems(kwargs):
            if diff.shape[0] != self.blobs[top].shape[0]:
                raise Exception('Diff is not batch sized')
            self.blobs[top].diff[...] = diff

    self._backward(start_ind, end_ind)

    # Unpack diffs to extract
    return {out: self.blobs[out].diff for out in outputs}