Exemple #1
0
 def test_make_random_conv2D(self):
     """
     Make random filters
     """
     default_axes = ('c', 0, 1, 'b')
     conv2d = make_random_conv2D(1, 16, default_axes, default_axes,
                                 16, (2, 2))
     f = theano.function([self.image_tensor],
                         conv2d.lmul(self.image_tensor))
     assert f(self.image).shape == (16, 2, 2, 1)
     assert conv2d.output_axes == default_axes
Exemple #2
0
    def set_input_space(self, space):
        """ Note: this resets parameters! """

        self.input_space = space

        if not isinstance(self.input_space, Conv2DSpace):
            raise TypeError(
                "The input to a convolutional layer should be a Conv2DSpace, "
                " but layer " + self.layer_name + " got " + str(type(self.input_space))
            )
        # note: I think the desired space thing is actually redundant,
        # since LinearTransform will also dimshuffle the axes if needed
        # It's not hurting anything to have it here but we could reduce
        # code complexity by removing it
        self.desired_space = Conv2DSpace(shape=space.shape, channels=space.num_channels, axes=("c", 0, 1, "b"))

        ch = self.desired_space.num_channels
        rem = ch % 4
        if ch > 3 and rem != 0:
            self.dummy_channels = 4 - rem
        else:
            self.dummy_channels = 0
        self.dummy_space = Conv2DSpace(
            shape=space.shape, channels=space.num_channels + self.dummy_channels, axes=("c", 0, 1, "b")
        )

        rng = self.mlp.rng

        output_shape = [
            self.input_space.shape[0] + 2 * self.pad - self.kernel_shape[0] + 1,
            self.input_space.shape[1] + 2 * self.pad - self.kernel_shape[1] + 1,
        ]

        def handle_kernel_shape(idx):
            if self.kernel_shape[idx] < 1:
                raise ValueError(
                    "kernel must have strictly positive size on all axes but has shape: " + str(self.kernel_shape)
                )
            if output_shape[idx] <= 0:
                if self.fix_kernel_shape:
                    self.kernel_shape[idx] = self.input_space.shape[idx] + 2 * self.pad
                    assert self.kernel_shape[idx] != 0
                    output_shape[idx] = 1
                    warnings.warn("Had to change the kernel shape to make network feasible")
                else:
                    raise ValueError("kernel too big for input (even with zero padding)")

        map(handle_kernel_shape, [0, 1])

        self.detector_space = Conv2DSpace(
            shape=output_shape, num_channels=self.detector_channels, axes=("c", 0, 1, "b")
        )

        def handle_pool_shape(idx):
            if self.pool_shape[idx] < 1:
                raise ValueError("bad pool shape: " + str(self.pool_shape))
            if self.pool_shape[idx] > output_shape[idx]:
                if self.fix_pool_shape:
                    assert output_shape[idx] > 0
                    self.pool_shape[idx] = output_shape[idx]
                else:
                    raise ValueError("Pool shape exceeds detector layer shape on axis %d" % idx)

        map(handle_pool_shape, [0, 1])

        assert self.pool_shape[0] == self.pool_shape[1]
        assert self.pool_stride[0] == self.pool_stride[1]
        assert all(isinstance(elem, py_integer_types) for elem in self.pool_stride)
        if self.pool_stride[0] > self.pool_shape[0]:
            if self.fix_pool_stride:
                warnings.warn("Fixing the pool stride")
                ps = self.pool_shape[0]
                assert isinstance(ps, py_integer_types)
                self.pool_stride = [ps, ps]
            else:
                raise ValueError("Stride too big.")
        assert all(isinstance(elem, py_integer_types) for elem in self.pool_stride)

        check_cuda()

        if self.irange is not None:
            self.transformer = conv2d_c01b.make_random_conv2D(
                irange=self.irange,
                input_axes=self.desired_space.axes,
                output_axes=self.detector_space.axes,
                input_channels=self.dummy_space.num_channels,
                output_channels=self.detector_space.num_channels,
                kernel_shape=self.kernel_shape,
                subsample=(1, 1),
                pad=self.pad,
                partial_sum=self.partial_sum,
                rng=rng,
            )
        W, = self.transformer.get_params()
        W.name = "W"

        if self.tied_b:
            self.b = sharedX(np.zeros((self.detector_space.num_channels)) + self.init_bias)
        else:
            self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
        self.b.name = "b"

        print "Input shape: ", self.input_space.shape
        print "Detector space: ", self.detector_space.shape

        assert self.detector_space.num_channels >= 16

        dummy_detector = sharedX(self.detector_space.get_origin_batch(2)[0:16, :, :, :])

        dummy_p = max_pool_c01b(
            c01b=dummy_detector,
            pool_shape=self.pool_shape,
            pool_stride=self.pool_stride,
            image_shape=self.detector_space.shape,
        )
        dummy_p = dummy_p.eval()
        self.output_space = Conv2DSpace(
            shape=[dummy_p.shape[1], dummy_p.shape[2]], num_channels=self.num_channels, axes=("c", 0, 1, "b")
        )

        print "Output space: ", self.output_space.shape
Exemple #3
0
def setup_deconv_detector_layer_c01b(layer, input_space, rng, irange="not specified"):
    """
    layer. This function sets up only the detector layer.

    Does the following:

    * raises a RuntimeError if cuda is not available
    * sets layer.input_space to input_space
    * sets up addition of dummy channels for compatibility with cuda-convnet:

      - layer.dummy_channels: # of dummy channels that need to be added
        (You might want to check this and raise an Exception if it's not 0)
      - layer.dummy_space: The Conv2DSpace representing the input with dummy
        channels added

    * sets layer.detector_space to the space for the detector layer
    * sets layer.transformer to be a Conv2D instance
    * sets layer.b to the right value

    Parameters
    ----------
    layer : object
        Any python object that allows the modifications described below and
        has the following attributes:

          * pad : int describing amount of zero padding to add
          * kernel_shape : 2-element tuple or list describing spatial shape of
            kernel
          * fix_kernel_shape : bool, if true, will shrink the kernel shape to
            make it feasible, as needed (useful for hyperparameter searchers)
          * detector_channels : The number of channels in the detector layer
          * init_bias : numeric constant added to a tensor of zeros to
            initialize the bias
          * tied_b : If true, biases are shared across all spatial locations
    input_space : WRITEME
        A Conv2DSpace to be used as input to the layer
    rng : WRITEME
        A numpy RandomState or equivalent
    """

    if irange != "not specified":
        raise AssertionError(
            "There was a bug in setup_detector_layer_c01b."
            "It uses layer.irange instead of the irange parameter to the "
            "function. The irange parameter is now disabled by this "
            "AssertionError, so that this error message can alert you that "
            "the bug affected your code and explain why the interface is "
            "changing. The irange parameter to the function and this "
            "error message may be removed after April 21, 2014."
        )

    # Use "self" to refer to layer from now on, so we can pretend we're
    # just running in the set_input_space method of the layer
    self = layer

    # Make sure cuda is available
    check_cuda(str(type(self)))

    # Validate input
    if not isinstance(input_space, Conv2DSpace):
        raise TypeError("The input to a convolutional layer should be a "
                        "Conv2DSpace, but layer " + self.layer_name + " got " +
                        str(type(self.input_space)))

    if not hasattr(self, 'detector_channels'):
        raise ValueError("layer argument must have a 'detector_channels' "
                         "attribute specifying how many channels to put in "
                         "the convolution kernel stack.")

    # Store the input space
    self.input_space = input_space

    # Make sure number of channels is supported by cuda-convnet
    # (multiple of 4 or <= 3)
    # If not supported, pad the input with dummy channels
    ch = self.detector_channels
    rem = ch % 4
    if ch > 3 and rem != 0:
        raise NotImplementedError("Need to do dummy channels on the output")
    #    self.dummy_channels = 4 - rem
    #else:
    #    self.dummy_channels = 0
    #self.dummy_space = Conv2DSpace(
    #    shape=input_space.shape,
    #    channels=input_space.num_channels + self.dummy_channels,
    #    axes=('c', 0, 1, 'b')
    #)

    if hasattr(self, 'output_stride'):
        kernel_stride = self.output_stride
    else:
        assert False # not sure if I got the name right, remove this assert if I did
        kernel_stride = [1, 1]


    #o_sh = int(np.ceil((i_sh + 2. * self.pad - k_sh) / float(k_st))) + 1
    #o_sh -1 = np.ceil((i_sh + 2. * self.pad - k_sh) / float(k_st))
    #inv_ceil(o_sh -1) = (i_sh + 2. * self.pad - k_sh) / float(k_st)
    #float(k_st) inv_cel(o_sh -1) = (i_sh + 2 * self.pad -k_sh)
    # i_sh = k_st inv_ceil(o_sh-1) - 2 * self.pad + k_sh

    output_shape = \
        [k_st * (i_sh - 1) - 2 * self.pad_out + k_sh
         for i_sh, k_sh, k_st in zip(self.input_space.shape,
                                     self.kernel_shape, kernel_stride)]


    if self.input_space.num_channels < 16:
        raise ValueError("Cuda-convnet requires the input to lmul_T to have "
                         "at least 16 channels.")

    self.detector_space = Conv2DSpace(shape=output_shape,
                                      num_channels=self.detector_channels,
                                      axes=('c', 0, 1, 'b'))

    if hasattr(self, 'partial_sum'):
        partial_sum = self.partial_sum
    else:
        partial_sum = 1

    if hasattr(self, 'sparse_init') and self.sparse_init is not None:
        self.transformer = \
            checked_call(make_sparse_random_conv2D,
                         OrderedDict([('num_nonzero', self.sparse_init),
                                      ('input_space', self.detector_space),
                                      ('output_space', self.input_space),
                                      ('kernel_shape', self.kernel_shape),
                                      ('pad', self.pad),
                                      ('partial_sum', partial_sum),
                                      ('kernel_stride', kernel_stride),
                                      ('rng', rng)]))
    else:
        self.transformer = make_random_conv2D(
            irange=self.irange,
            input_axes=self.detector_space.axes,
            output_axes=self.input_space.axes,
            input_channels=self.detector_space.num_channels,
            output_channels=self.input_space.num_channels,
            kernel_shape=self.kernel_shape,
            pad=self.pad_out,
            partial_sum=partial_sum,
            kernel_stride=kernel_stride,
            rng=rng,
            input_shape=self.detector_space.shape
        )

    W, = self.transformer.get_params()
    W.name = self.layer_name + '_W'

    if self.tied_b:
        self.b = sharedX(np.zeros(self.detector_space.num_channels) +
                         self.init_bias)
    else:
        self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
    self.b.name = self.layer_name + '_b'

    logger.info('Input shape: {0}'.format(self.input_space.shape))
    print layer.layer_name + ' detector space: {0}'.format(self.detector_space.shape)
Exemple #4
0
def setup_deconv_detector_layer_c01b(layer,
                                     input_space,
                                     rng,
                                     irange="not specified"):
    """
    layer. This function sets up only the detector layer.

    Does the following:

    * raises a RuntimeError if cuda is not available
    * sets layer.input_space to input_space
    * sets up addition of dummy channels for compatibility with cuda-convnet:

      - layer.dummy_channels: # of dummy channels that need to be added
        (You might want to check this and raise an Exception if it's not 0)
      - layer.dummy_space: The Conv2DSpace representing the input with dummy
        channels added

    * sets layer.detector_space to the space for the detector layer
    * sets layer.transformer to be a Conv2D instance
    * sets layer.b to the right value

    Parameters
    ----------
    layer : object
        Any python object that allows the modifications described below and
        has the following attributes:

          * pad : int describing amount of zero padding to add
          * kernel_shape : 2-element tuple or list describing spatial shape of
            kernel
          * fix_kernel_shape : bool, if true, will shrink the kernel shape to
            make it feasible, as needed (useful for hyperparameter searchers)
          * detector_channels : The number of channels in the detector layer
          * init_bias : numeric constant added to a tensor of zeros to
            initialize the bias
          * tied_b : If true, biases are shared across all spatial locations
    input_space : WRITEME
        A Conv2DSpace to be used as input to the layer
    rng : WRITEME
        A numpy RandomState or equivalent
    """

    if irange != "not specified":
        raise AssertionError(
            "There was a bug in setup_detector_layer_c01b."
            "It uses layer.irange instead of the irange parameter to the "
            "function. The irange parameter is now disabled by this "
            "AssertionError, so that this error message can alert you that "
            "the bug affected your code and explain why the interface is "
            "changing. The irange parameter to the function and this "
            "error message may be removed after April 21, 2014.")

    # Use "self" to refer to layer from now on, so we can pretend we're
    # just running in the set_input_space method of the layer
    self = layer

    # Make sure cuda is available
    check_cuda(str(type(self)))

    # Validate input
    if not isinstance(input_space, Conv2DSpace):
        raise TypeError("The input to a convolutional layer should be a "
                        "Conv2DSpace, but layer " + self.layer_name + " got " +
                        str(type(self.input_space)))

    if not hasattr(self, 'detector_channels'):
        raise ValueError("layer argument must have a 'detector_channels' "
                         "attribute specifying how many channels to put in "
                         "the convolution kernel stack.")

    # Store the input space
    self.input_space = input_space

    # Make sure number of channels is supported by cuda-convnet
    # (multiple of 4 or <= 3)
    # If not supported, pad the input with dummy channels
    ch = self.detector_channels
    rem = ch % 4
    if ch > 3 and rem != 0:
        raise NotImplementedError("Need to do dummy channels on the output")
    #    self.dummy_channels = 4 - rem
    #else:
    #    self.dummy_channels = 0
    #self.dummy_space = Conv2DSpace(
    #    shape=input_space.shape,
    #    channels=input_space.num_channels + self.dummy_channels,
    #    axes=('c', 0, 1, 'b')
    #)

    if hasattr(self, 'output_stride'):
        kernel_stride = self.output_stride
    else:
        assert False  # not sure if I got the name right, remove this assert if I did
        kernel_stride = [1, 1]

    #o_sh = int(np.ceil((i_sh + 2. * self.pad - k_sh) / float(k_st))) + 1
    #o_sh -1 = np.ceil((i_sh + 2. * self.pad - k_sh) / float(k_st))
    #inv_ceil(o_sh -1) = (i_sh + 2. * self.pad - k_sh) / float(k_st)
    #float(k_st) inv_cel(o_sh -1) = (i_sh + 2 * self.pad -k_sh)
    # i_sh = k_st inv_ceil(o_sh-1) - 2 * self.pad + k_sh

    output_shape = \
        [k_st * (i_sh - 1) - 2 * self.pad_out + k_sh
         for i_sh, k_sh, k_st in zip(self.input_space.shape,
                                     self.kernel_shape, kernel_stride)]

    if self.input_space.num_channels < 16:
        raise ValueError("Cuda-convnet requires the input to lmul_T to have "
                         "at least 16 channels.")

    self.detector_space = Conv2DSpace(shape=output_shape,
                                      num_channels=self.detector_channels,
                                      axes=('c', 0, 1, 'b'))

    if hasattr(self, 'partial_sum'):
        partial_sum = self.partial_sum
    else:
        partial_sum = 1

    if hasattr(self, 'sparse_init') and self.sparse_init is not None:
        self.transformer = \
            checked_call(make_sparse_random_conv2D,
                         OrderedDict([('num_nonzero', self.sparse_init),
                                      ('input_space', self.detector_space),
                                      ('output_space', self.input_space),
                                      ('kernel_shape', self.kernel_shape),
                                      ('pad', self.pad),
                                      ('partial_sum', partial_sum),
                                      ('kernel_stride', kernel_stride),
                                      ('rng', rng)]))
    else:
        self.transformer = make_random_conv2D(
            irange=self.irange,
            input_axes=self.detector_space.axes,
            output_axes=self.input_space.axes,
            input_channels=self.detector_space.num_channels,
            output_channels=self.input_space.num_channels,
            kernel_shape=self.kernel_shape,
            pad=self.pad_out,
            partial_sum=partial_sum,
            kernel_stride=kernel_stride,
            rng=rng,
            input_shape=self.detector_space.shape)

    W, = self.transformer.get_params()
    W.name = self.layer_name + '_W'

    if self.tied_b:
        self.b = sharedX(
            np.zeros(self.detector_space.num_channels) + self.init_bias)
    else:
        self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
    self.b.name = self.layer_name + '_b'

    logger.info('Input shape: {0}'.format(self.input_space.shape))
    print layer.layer_name + ' detector space: {0}'.format(
        self.detector_space.shape)
Exemple #5
0
    def set_input_space(self, space):

        self.input_space = space

        if not isinstance(space, Conv2DSpace):
            raise BadInputSpaceError("ConvRectifiedLinear.set_input_space "
                                     "expected a Conv2DSpace, got " +
                                     str(space) + " of type " +
                                     str(type(space)))

        rng = self.mlp.rng

        if self.border_mode == 'valid':
            output_shape = [(self.input_space.shape[0]-self.kernel_shape[0]) /
                            self.kernel_stride[0] + 1,
                            (self.input_space.shape[1]-self.kernel_shape[1]) /
                            self.kernel_stride[1] + 1]
        elif self.border_mode == 'full':
            output_shape = [(self.input_space.shape[0]+self.kernel_shape[0]) /
                            self.kernel_stride[0] - 1,
                            (self.input_space.shape[1]+self.kernel_shape[1]) /
                            self.kernel_stride[1] - 1]

        self.detector_space = Conv2DSpace(shape=output_shape,
                                          num_channels=self.output_channels,
                                          axes=('c', 0, 1, 'b'))

        if self.irange is not None:
            assert self.sparse_init is None
            self.transformer = conv2d.make_random_conv2D(
                irange=self.irange,
                input_channels=self.input_space.num_channels,
                input_axes=self.input_space.axes,
                output_axes=self.detector_space.axes,
                output_channels=self.detector_space.num_channels,
                kernel_shape=self.kernel_shape,
                kernel_stride=self.kernel_stride,
                rng=rng)
        elif self.sparse_init is not None:
            self.transformer = conv2d.make_sparse_random_conv2D(
                num_nonzero=self.sparse_init,
                input_space=self.input_space,
                output_space=self.detector_space,
                kernel_shape=self.kernel_shape,
                batch_size=self.mlp.batch_size,
                subsample=self.kernel_stride,
                border_mode=self.border_mode,
                rng=rng)
        W, = self.transformer.get_params()
        W.name = 'W'

        self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
        self.b.name = 'b'

        print 'Input shape: ', self.input_space.shape
        print 'Detector space: ', self.detector_space.shape

        assert self.pool_type in ['max', 'mean']

        dummy_batch_size = self.mlp.batch_size
        if dummy_batch_size is None:
            dummy_batch_size = 2
        dummy_detector = sharedX(
            self.detector_space.get_origin_batch(dummy_batch_size))
        if self.pool_type == 'max':
            dummy_p = max_pool_c01b(c01b=dummy_detector,
                               pool_shape=self.pool_shape,
                               pool_stride=self.pool_stride,
                               image_shape=self.detector_space.shape)
        elif self.pool_type == 'mean':
            dummy_p = mean_pool(bc01=dummy_detector,
                                pool_shape=self.pool_shape,
                                pool_stride=self.pool_stride,
                                image_shape=self.detector_space.shape)
        dummy_p = dummy_p.eval()
        self.output_space = Conv2DSpace(shape=[dummy_p.shape[2],
                                               dummy_p.shape[3]],
                                        num_channels=self.output_channels,
                                        axes=('c', 0, 1, 'b'))

        print 'Output space: ', self.output_space.shape
Exemple #6
0
    def set_input_space(self, space):

        self.input_space = space

        if not isinstance(space, Conv2DSpace):
            raise BadInputSpaceError("ConvRectifiedLinear.set_input_space "
                                     "expected a Conv2DSpace, got " +
                                     str(space) + " of type " +
                                     str(type(space)))

        rng = self.mlp.rng

        if self.border_mode == 'valid':
            output_shape = [
                (self.input_space.shape[0] - self.kernel_shape[0]) /
                self.kernel_stride[0] + 1,
                (self.input_space.shape[1] - self.kernel_shape[1]) /
                self.kernel_stride[1] + 1
            ]
        elif self.border_mode == 'full':
            output_shape = [
                (self.input_space.shape[0] + self.kernel_shape[0]) /
                self.kernel_stride[0] - 1,
                (self.input_space.shape[1] + self.kernel_shape[1]) /
                self.kernel_stride[1] - 1
            ]

        self.detector_space = Conv2DSpace(shape=output_shape,
                                          num_channels=self.output_channels,
                                          axes=('c', 0, 1, 'b'))

        if self.irange is not None:
            assert self.sparse_init is None
            self.transformer = conv2d.make_random_conv2D(
                irange=self.irange,
                input_channels=self.input_space.num_channels,
                input_axes=self.input_space.axes,
                output_axes=self.detector_space.axes,
                output_channels=self.detector_space.num_channels,
                kernel_shape=self.kernel_shape,
                kernel_stride=self.kernel_stride,
                rng=rng)
        elif self.sparse_init is not None:
            self.transformer = conv2d.make_sparse_random_conv2D(
                num_nonzero=self.sparse_init,
                input_space=self.input_space,
                output_space=self.detector_space,
                kernel_shape=self.kernel_shape,
                batch_size=self.mlp.batch_size,
                subsample=self.kernel_stride,
                border_mode=self.border_mode,
                rng=rng)
        W, = self.transformer.get_params()
        W.name = 'W'

        self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
        self.b.name = 'b'

        print 'Input shape: ', self.input_space.shape
        print 'Detector space: ', self.detector_space.shape

        assert self.pool_type in ['max', 'mean']

        dummy_batch_size = self.mlp.batch_size
        if dummy_batch_size is None:
            dummy_batch_size = 2
        dummy_detector = sharedX(
            self.detector_space.get_origin_batch(dummy_batch_size))
        if self.pool_type == 'max':
            dummy_p = max_pool_c01b(c01b=dummy_detector,
                                    pool_shape=self.pool_shape,
                                    pool_stride=self.pool_stride,
                                    image_shape=self.detector_space.shape)
        elif self.pool_type == 'mean':
            dummy_p = mean_pool(bc01=dummy_detector,
                                pool_shape=self.pool_shape,
                                pool_stride=self.pool_stride,
                                image_shape=self.detector_space.shape)
        dummy_p = dummy_p.eval()
        self.output_space = Conv2DSpace(
            shape=[dummy_p.shape[2], dummy_p.shape[3]],
            num_channels=self.output_channels,
            axes=('c', 0, 1, 'b'))

        print 'Output space: ', self.output_space.shape
Exemple #7
0
    def set_input_space(self, space):
        """ Note: this resets parameters! """

        self.input_space = space

        if not isinstance(self.input_space, Conv2DSpace):
            raise TypeError("The input to a convolutional layer should be a Conv2DSpace, "
                    " but layer " + self.layer_name + " got "+str(type(self.input_space)))
        # note: I think the desired space thing is actually redundant,
        # since LinearTransform will also dimshuffle the axes if needed
        # It's not hurting anything to have it here but we could reduce
        # code complexity by removing it
        self.desired_space = Conv2DSpace(shape=space.shape,
                                         channels=space.num_channels,
                                         axes=('c', 0, 1, 'b'))

        ch = self.desired_space.num_channels
        rem = ch % 4
        if ch > 3 and rem != 0:
            self.dummy_channels = 4 - rem
        else:
            self.dummy_channels = 0
        self.dummy_space = Conv2DSpace(shape=space.shape,
                                       channels=space.num_channels + self.dummy_channels,
                                       axes=('c', 0, 1, 'b'))

        rng = self.mlp.rng

        output_shape = [self.input_space.shape[0] + 2 * self.pad - self.kernel_shape[0] + 1,
                        self.input_space.shape[1] + 2 * self.pad - self.kernel_shape[1] + 1]

        def handle_kernel_shape(idx):
            if self.kernel_shape[idx] < 1:
                raise ValueError("kernel must have strictly positive size on all axes but has shape: "+str(self.kernel_shape))
            if output_shape[idx] <= 0:
                if self.fix_kernel_shape:
                    self.kernel_shape[idx] = self.input_space.shape[idx] + 2 * self.pad
                    assert self.kernel_shape[idx] != 0
                    output_shape[idx] = 1
                    warnings.warn("Had to change the kernel shape to make network feasible")
                else:
                    raise ValueError("kernel too big for input (even with zero padding)")

        map(handle_kernel_shape, [0, 1])

        self.detector_space = Conv2DSpace(shape=output_shape,
                                          num_channels = self.detector_channels,
                                          axes = ('c', 0, 1, 'b'))

        def handle_pool_shape(idx):
            if self.pool_shape[idx] < 1:
                raise ValueError("bad pool shape: " + str(self.pool_shape))
            if self.pool_shape[idx] > output_shape[idx]:
                if self.fix_pool_shape:
                    assert output_shape[idx] > 0
                    self.pool_shape[idx] = output_shape[idx]
                else:
                    raise ValueError("Pool shape exceeds detector layer shape on axis %d" % idx)

        map(handle_pool_shape, [0, 1])

        assert self.pool_shape[0] == self.pool_shape[1]
        assert self.pool_stride[0] == self.pool_stride[1]
        assert all(isinstance(elem, py_integer_types) for elem in self.pool_stride)
        if self.pool_stride[0] > self.pool_shape[0]:
            if self.fix_pool_stride:
                warnings.warn("Fixing the pool stride")
                ps = self.pool_shape[0]
                assert isinstance(ps, py_integer_types)
                self.pool_stride = [ps, ps]
            else:
                raise ValueError("Stride too big.")
        assert all(isinstance(elem, py_integer_types) for elem in self.pool_stride)


        check_cuda()

        if self.irange is not None:
            self.transformer = conv2d_c01b.make_random_conv2D(
                                                              irange = self.irange,
                                                              input_axes = self.desired_space.axes,
                                                              output_axes = self.detector_space.axes,
                                                              input_channels = self.dummy_space.num_channels,
                                                              output_channels = self.detector_space.num_channels,
                                                              kernel_shape = self.kernel_shape,
                                                              subsample = (1,1),
                                                              pad = self.pad,
                                                              partial_sum = self.partial_sum,
                                                              rng = rng)
        W, = self.transformer.get_params()
        W.name = 'W'


        if self.tied_b:
            self.b = sharedX(np.zeros((self.detector_space.num_channels)) + self.init_bias)
        else:
            self.b = sharedX(self.detector_space.get_origin() + self.init_bias)
        self.b.name = 'b'

        print 'Input shape: ', self.input_space.shape
        print 'Detector space: ', self.detector_space.shape

        assert self.detector_space.num_channels >= 16

        dummy_detector = sharedX(self.detector_space.get_origin_batch(2)[0:16,:,:,:])

        dummy_p = max_pool_c01b(c01b=dummy_detector, pool_shape=self.pool_shape,
                                pool_stride=self.pool_stride,
                                image_shape=self.detector_space.shape)
        dummy_p = dummy_p.eval()
        self.output_space = Conv2DSpace(shape=[dummy_p.shape[1], dummy_p.shape[2]],
                                        num_channels = self.num_channels, axes = ('c', 0, 1, 'b') )

        print 'Output space: ', self.output_space.shape