Esempio n. 1
0
    def __init__(self, prev_layer, ksize, stride):
        """
        :param prev_layer: The previous Layer object in the network
        :param ksize: The kernels size as a python list [k_height, k_width]
        :param stride: The stride
        """

        self._prev_layer = prev_layer
        self._ksize = ksize
        self._stride = stride

        in_channels, in_height, in_width = prev_layer.out_shape()
        k_height, k_width = ksize
        out_height = (np.floor((in_height - k_height) / stride) + 1).astype(np.int32)
        out_width = (np.floor((in_width - k_width) / stride) + 1).astype(np.int32)

        self._out_shape = [in_channels, out_height, out_width]
        prevlayer_surface = prev_layer.surface().reshape(in_channels, 1, in_height, in_width)
        surface_col, _ = im2col(prevlayer_surface, [in_channels, in_channels, *self._ksize], self._stride)
        self._init_idx_max = [surface_col.argmax(0).astype(np.int32),
                              np.arange(in_channels * out_height * out_width, dtype=np.int32)]
        self._idx_max = [self._init_idx_max[0].copy(), self._init_idx_max[1].copy()]
        self._recompute_coords = np.zeros([out_height, out_width], dtype=np.bool)

        self._cache_surface = None
        self._cache_layer_actfn = None
        self._cache_conv_actfn = None
    def compute(self, events, delta_leak):

        # Retrieves variables and shapes from previous layer
        prevlayer_surface = self._prev_layer.surface()
        prevlayer_shape = self._prev_layer.out_shape()

        in_channels, in_height, in_width = prevlayer_shape
        k_height, k_width = self._ksize

        # Makes the channels the batch dimension
        prevlayer_surface = prevlayer_surface.reshape(in_channels, 1,
                                                      in_height, in_width)
        # surface_col: [k_height * k_width, in_channels * out_h * out_w]
        surface_col, _ = im2col(prevlayer_surface,
                                [in_channels, in_channels, k_height, k_width],
                                self._stride)
        idx_max_patches = np.argmax(surface_col, axis=0)
        changed_idx_mask = np.not_equal(
            idx_max_patches, self._idx_max[0]).reshape(self._out_shape)
        changed_idx_mask = np.any(changed_idx_mask, axis=0)

        # Input events are always forwarded
        y, x = events
        changed_idx_mask[y // self._stride, x // self._stride] = True
        new_events = np.where(changed_idx_mask)

        # Updates the indices
        self._idx_max[0] = idx_max_patches

        # Resets the cached values
        self._cache_surface = None
        self._cache_layer_actfn = None
        self._cache_conv_actfn = None

        return new_events, delta_leak
Esempio n. 3
0
    def conv_actfn(self):

        if self._cache_conv_actfn is None:
            in_channels, in_height, in_width = self._prev_layer.out_shape()
            prevlayer_conv_actfn = self._prev_layer.conv_actfn()

            # Makes the channels the batch dimension
            prevlayer_conv_actfn = prevlayer_conv_actfn.reshape(in_channels, 1, in_height, in_width)
            conv_actfn_col, _ = im2col(prevlayer_conv_actfn, [in_channels, in_channels, *self._ksize], self._stride)
            self._cache_conv_actfn = conv_actfn_col[tuple(self._idx_max)].reshape(self._out_shape)

        return self._cache_conv_actfn
Esempio n. 4
0
    def surface(self):

        if self._cache_surface is None:
            in_channels, in_height, in_width = self._prev_layer.out_shape()
            prevlayer_surface = self._prev_layer.surface()

            # Makes the channels the batch dimension
            prevlayer_surface = prevlayer_surface.reshape(in_channels, 1, in_height, in_width)
            surface_col, _ = im2col(prevlayer_surface, [in_channels, in_channels, *self._ksize], self._stride)
            self._cache_surface = surface_col[tuple(self._idx_max)].reshape(self._out_shape)

        return self._cache_surface
Esempio n. 5
0
def conv2d(image, kernel, bias=None, padding='VALID', stride=1):
    """
    Computes the convolution of the kernel on the provided image.

    :param image: The image as a [batch, in_channel, height, width] (or [in_channel, height, width]) numpy ndarray
    :param kernel: The kernel to be convolved as a [out_channel, in_channel, k_height, k_width] ndarray
    :param bias: (optional) If provided, the bias will be added after the convolution operation.
    :param padding: (optional) A string representing the padding to be applied. 'VALID' is the only one currently
        supported.
    :param stride: (optional, default 1) The stride, this value will be used for both vertical and horizontal  stride.
    :return: The convolved image as a numpy's ndarray of shape [batch, out_channel, out_h, out_w]
    """

    image = np.ascontiguousarray(image)

    batch, img_channel, img_height, img_width = image.shape if image.ndim == 4 else [
        1, *image.shape
    ]
    out_channel, _, k_height, k_width = kernel.shape

    if padding == 'SAME':
        if img_height % stride == 0:
            pad_along_height = max(k_height - stride, 0)
        else:
            pad_along_height = max(k_height - (img_height % stride), 0)
        if img_width % stride == 0:
            pad_along_width = max(k_width - stride, 0)
        else:
            pad_along_width = max(k_width - (img_width % stride), 0)

        pad_top = pad_along_height // 2
        pad_left = pad_along_width // 2
        image = np.pad(image, ((0, 0), (pad_top, pad_along_height - pad_top),
                               (pad_left, pad_along_width - pad_left)),
                       mode='constant')

    img_cols, (out_h, out_w) = im2col(image, kernel.shape, stride)
    kernel_rows = kernel.reshape(out_channel, -1)

    conv = kernel_rows.dot(img_cols)
    if bias is not None:
        bias_rows = bias.reshape(out_channel, 1)
        conv = conv + bias_rows

    if image.ndim == 4:
        conv = conv.reshape(out_channel, batch, out_h,
                            out_w).transpose(1, 0, 2, 3)
    else:
        conv = conv.reshape(out_channel, out_h, out_w)

    return conv
Esempio n. 6
0
    def maxpool(self, input, ksize, stride):
        in_channels, in_height, in_width = input.shape
        k_height, k_width = ksize

        input = input.reshape(in_channels, 1, in_height, in_width)
        frame_cols, (out_h, out_w) = im2col(
            input, [in_channels, in_channels, k_height, k_width], stride)
        argmax_idx = np.argmax(frame_cols, axis=0)
        frame_pool = frame_cols[
            argmax_idx,
            np.arange(in_channels * out_h * out_w, dtype=np.int32)]
        frame_pool = frame_pool.reshape(in_channels, out_h, out_w)

        return frame_pool