def _backward(self, grad_act, input_act):
        # this is probably the trickiest method in this entire module...

        # input activation gradient -- notice that we have to flip the filters horizontally and
        # vertically
        rev_filters = np.fliplr(np.flipud(self.filters_))

        # note: opencv doesn't like arbitrary slices of numpy arrays, so we need to shuffle the
        # dimensions around a little bit

        # rev_filters will now be NUM_FILTERS x NUM_CHANNELS x ...
        rev_filters = np.rollaxis(np.rollaxis(rev_filters, 2, 0), 3, 0).copy()
        padded_grad_act = padarray(grad_act, self.filter_pad)
        # padded_grad_act will now be NUM_FILTERS x NUM_EXAMPLES x ...
        padded_grad_act = np.rollaxis(padded_grad_act, 3, 0).copy()
        grad_input_act = np.zeros(input_act.shape, dtype='float32')
        for z in xrange(input_act.shape[0]):
            for c in xrange(input_act.shape[-1]):
                for f in xrange(self.filters_.shape[-1]):
                    grad_input_act[z,:,:,c] +=  filter2D(padded_grad_act[f,z], rev_filters[f,c])

        # grad_input_act = grad_input_act.sum(-1)

        # params gradient
        grad_params = np.zeros((input_act.shape[1:4] + (grad_act.shape[-1],)), dtype='float32')
        # grad_act_ will now be NUM_FILTERS x NUM_EXAMPLES x ...
        grad_act_ = np.rollaxis(grad_act, 3, 0).copy()
        # padded_grad_act will now be NUM_CHANNELS x NUM_EXAMPLES x ...
        input_act = np.rollaxis(input_act, 3, 0).copy()
        for n in xrange(input_act.shape[1]):
            for c in xrange(input_act.shape[0]):
                for f in xrange(grad_act.shape[-1]):
                    grad_params[:,:,c,f] +=  filter2D(input_act[c,n], grad_act_[f,n])
        grad_params /= input_act.shape[1]

        r_border, c_border = grad_act.shape[1]/2, grad_act.shape[2]/2
        if grad_act.shape[1] %2 == 0:
            grad_params = grad_params[r_border:-r_border+1, c_border:-c_border+1,...]
        else:
            grad_params = grad_params[r_border:-r_border, c_border:-c_border,...]
        assert grad_params.shape == self.filters_.shape, 'wrong param grad shape'

        return grad_input_act, grad_params.ravel()
dataset/ETHPy150Open bbabenko/simple_convnet/simple_convnet/convnet.py/ConvLayer._backward/original