Exemple #1
0
def test_convolutional():
    x = tensor.tensor4("x")
    num_channels = 4
    num_filters = 3
    batch_size = 5
    filter_size = (3, 3)
    conv = Convolutional(
        filter_size,
        num_filters,
        num_channels,
        image_size=(17, 13),
        weights_init=Constant(1.0),
        biases_init=Constant(5.0),
    )
    conv.initialize()
    y = conv.apply(x)
    func = function([x], y)

    x_val = numpy.ones((batch_size, num_channels, 17, 13), dtype=theano.config.floatX)
    assert_allclose(
        func(x_val), numpy.prod(filter_size) * num_channels * numpy.ones((batch_size, num_filters, 15, 11)) + 5
    )
    conv.image_size = (17, 13)
    conv.batch_size = 2  # This should have effect on get_dim
    assert conv.get_dim("output") == (num_filters, 15, 11)
    def conv_layer(self, name, wt, bias, image_size):
        """Creates a Convolutional brick with the given name, weights,
        bias, and image_size."""

        layer = Convolutional(
            name=name,
            filter_size=wt.shape[0:2],
            num_channels=wt.shape[2],  # in
            num_filters=wt.shape[3],  # out
            weights_init=Constant(0),  # does not matter
            biases_init=Constant(0),  # does not matter
            tied_biases=True,
            border_mode='valid',
        )

        if image_size:
            layer.image_size = image_size

        layer.initialize()

        weights = self.to_bc01(wt)
        layer.parameters[0].set_value(weights.astype("float32"))  # W
        layer.parameters[1].set_value(bias.squeeze().astype("float32"))  # b

        return (layer, layer.get_dim("output")[1:3])
Exemple #3
0
def test_convolutional():
    x = tensor.tensor4('x')
    num_channels = 4
    num_filters = 3
    batch_size = 5
    filter_size = (3, 3)
    conv = Convolutional(filter_size,
                         num_filters,
                         num_channels,
                         image_size=(17, 13),
                         weights_init=Constant(1.),
                         biases_init=Constant(5.))
    conv.initialize()
    y = conv.apply(x)
    func = function([x], y)

    x_val = numpy.ones((batch_size, num_channels, 17, 13),
                       dtype=theano.config.floatX)
    assert_allclose(
        func(x_val),
        numpy.prod(filter_size) * num_channels * numpy.ones(
            (batch_size, num_filters, 15, 11)) + 5)
    conv.image_size = (17, 13)
    conv.batch_size = 2  # This should have effect on get_dim
    assert conv.get_dim('output') == (num_filters, 15, 11)
Exemple #4
0
def test_no_input_size():
    # suppose x is outputted by some RNN
    x = tensor.tensor4('x')
    filter_size = (1, 3)
    num_filters = 2
    num_channels = 5
    c = Convolutional(filter_size,
                      num_filters,
                      num_channels,
                      tied_biases=True,
                      weights_init=Constant(1.),
                      biases_init=Constant(1.))
    c.initialize()
    out = c.apply(x)
    assert c.get_dim('output') == (2, None, None)
    assert out.ndim == 4

    c = Convolutional(filter_size,
                      num_filters,
                      num_channels,
                      tied_biases=False,
                      weights_init=Constant(1.),
                      biases_init=Constant(1.))
    assert_raises_regexp(ValueError, 'Cannot infer bias size \S+',
                         c.initialize)
Exemple #5
0
    def conv_layer(self, name, wt, bias, image_size):
        """Creates a Convolutional brick with the given name, weights,
        bias, and image_size."""

        layer = Convolutional(
            name=name,
            filter_size=wt.shape[0:2],
            num_channels=wt.shape[2],  # in
            num_filters=wt.shape[3],  # out
            weights_init=Constant(0),  # does not matter
            biases_init=Constant(0),  # does not matter
            tied_biases=True,
            border_mode="valid",
        )

        if image_size:
            layer.image_size = image_size

        layer.initialize()

        weights = self.to_bc01(wt)
        layer.parameters[0].set_value(weights.astype("float32"))  # W
        layer.parameters[1].set_value(bias.squeeze().astype("float32"))  # b

        return (layer, layer.get_dim("output")[1:3])
Exemple #6
0
class ConvolutionalActivation(Initializable):
    """A convolution followed by an activation function.
    Parameters
    ----------
    activation : :class:`.BoundApplication`
        The application method to apply after convolution (i.e.
        the nonlinear activation function)
    See Also
    --------
    :class:`Convolutional` : For the documentation of other parameters.
    """
    @lazy(allocation=['filter_size', 'num_filters', 'num_channels'])
    def __init__(self, activation, filter_size, num_filters, num_channels,
                 batch_size=None, image_size=None, step=(1, 1),
                 border_mode='valid', tied_biases=False, **kwargs):
        self.convolution = Convolutional(name='conv'+ kwargs['name'])
        self.bn = BatchNorm(name='bn'+ kwargs['name'])
        self.activation = activation
        self.filter_size = filter_size
        self.num_filters = num_filters
        self.num_channels = num_channels
        self.batch_size = batch_size
        self.image_size = image_size
        self.step = step
        self.border_mode = border_mode
        self.tied_biases = tied_biases
        super(ConvolutionalActivation, self).__init__(**kwargs)
        self.children = [self.convolution, self.bn, self.activation]
        

    def _push_allocation_config(self):
        for attr in ['filter_size', 'num_filters', 'step', 'border_mode',
                     'batch_size', 'num_channels', 'image_size',
                     'tied_biases']:
            setattr(self.convolution, attr, getattr(self, attr))
        setattr(self.bn, 'input_dim', self.num_filters)
        
    def get_dim(self, name):
        # TODO The name of the activation output doesn't need to be `output`
        return self.convolution.get_dim(name)
        
    def apply(self, input_):
        out = self.convolution.apply(input_)
        out = self.bn.apply(out)
        out = self.activation.apply(out)
        return out
        
    def inference(self, input_):
        out = self.convolution.apply(input_)
        out = self.bn.inference(out)
        out = self.activation.apply(out)
        return out
class ConvolutionalActivation(Sequence, Initializable):
    """A convolution followed by an activation function.
    Parameters
    ----------
    activation : :class:`.BoundApplication`
        The application method to apply after convolution (i.e.
        the nonlinear activation function)
    See Also
    --------
    :class:`Convolutional` for the other parameters.
    """
    @lazy(allocation=['filter_size', 'num_filters', 'num_channels'])
    def __init__(self,
                 activation,
                 filter_size,
                 num_filters,
                 num_channels,
                 batch_size=None,
                 image_size=None,
                 step=(1, 1),
                 border_mode='valid',
                 **kwargs):
        self.convolution = Convolutional()

        self.filter_size = filter_size
        self.num_filters = num_filters
        self.num_channels = num_channels
        self.batch_size = batch_size
        self.image_size = image_size
        self.step = step
        self.border_mode = border_mode

        super(ConvolutionalActivation, self).__init__(
            application_methods=[self.convolution.apply, activation], **kwargs)

    def _push_allocation_config(self):
        for attr in [
                'filter_size', 'num_filters', 'step', 'border_mode',
                'batch_size', 'num_channels', 'image_size'
        ]:
            setattr(self.convolution, attr, getattr(self, attr))

    def get_dim(self, name):
        # TODO The name of the activation output doesn't need to be `output`
        return self.convolution.get_dim(name)
Exemple #8
0
def test_no_input_size():
    # suppose x is outputted by some RNN
    x = tensor.tensor4('x')
    filter_size = (1, 3)
    num_filters = 2
    num_channels = 5
    c = Convolutional(filter_size, num_filters, num_channels, tied_biases=True,
                      weights_init=Constant(1.), biases_init=Constant(1.))
    c.initialize()
    out = c.apply(x)
    assert c.get_dim('output') == (2, None, None)
    assert out.ndim == 4

    c = Convolutional(filter_size, num_filters, num_channels,
                      tied_biases=False, weights_init=Constant(1.),
                      biases_init=Constant(1.))
    assert_raises_regexp(ValueError, 'Cannot infer bias size \S+',
                         c.initialize)
class ConvolutionalActivation(Sequence, Initializable):
    """A convolution followed by an activation function.
    Parameters
    ----------
    activation : :class:`.BoundApplication`
        The application method to apply after convolution (i.e.
        the nonlinear activation function)
    See Also
    --------
    :class:`Convolutional` for the other parameters.
    """
    
    @lazy(allocation=['filter_size', 'num_filters', 'num_channels'])
    def __init__(self, activation, filter_size, num_filters, num_channels,
                 batch_size=None, image_size=None, step=(1, 1),
                 border_mode='valid', **kwargs):
        self.convolution = Convolutional()

        self.filter_size = filter_size
        self.num_filters = num_filters
        self.num_channels = num_channels
        self.batch_size = batch_size
        self.image_size = image_size
        self.step = step
        self.border_mode = border_mode

        super(ConvolutionalActivation, self).__init__(
            application_methods=[self.convolution.apply, activation],
            **kwargs)

    def _push_allocation_config(self):
        for attr in ['filter_size', 'num_filters', 'step', 'border_mode',
                     'batch_size', 'num_channels', 'image_size']:
            setattr(self.convolution, attr, getattr(self, attr))

    def get_dim(self, name):
        # TODO The name of the activation output doesn't need to be `output`
        return self.convolution.get_dim(name)
Exemple #10
0
o = X.reshape((X.shape[0], 1, 28, 28))

l = Convolutional(filter_size=(5, 5),
                  num_filters=32,
                  num_channels=1,
                  image_size=(28, 28),
                  weights_init=IsotropicGaussian(std=0.01),
                  biases_init=IsotropicGaussian(std=0.01, mean=1.0),
                  use_bias=True,
                  border_mode="valid",
                  step=(1, 1))
l.initialize()
o = l.apply(o)

l = BatchNormalizationConv(input_shape=l.get_dim("output"),
                           B_init=IsotropicGaussian(std=0.01),
                           Y_init=IsotropicGaussian(std=0.01))
l.initialize()
o = l.apply(o)

o = Rectifier().apply(o)

l = MaxPooling(pooling_size=(2, 2), step=(2, 2), input_dim=l.get_dim("output"))
l.initialize()
o = l.apply(o)

#ll = Dropout(p_drop=0.5)
#ll.initialize()
#o = ll.apply(o)
Exemple #11
0
class ResidualConvolutional(Initializable):
    @lazy(allocation=['filter_size', 'num_filters', 'num_channels'])
    def __init__(self, filter_size, num_filters, num_channels,
                 batch_size=None,
                 mid_noise=False,
                 out_noise=False,
                 tied_noise=False,
                 tied_sigma=False,
                 noise_rate=None,
                 noise_batch_size=None,
                 prior_noise_level=None,
                 image_size=(None, None), step=(1, 1),
                 **kwargs):
        self.filter_size = filter_size
        self.num_filters = num_filters
        self.batch_size = batch_size
        self.num_channels = num_channels
        self.image_size = image_size
        self.mid_noise = mid_noise
        self.noise_batch_size = noise_batch_size
        self.noise_rate = noise_rate
        self.step = step
        self.border_mode = 'half'
        self.tied_biases = True
        depth = 2

        self.b0 = SpatialBatchNormalization(name='b0')
        self.r0 = Rectifier(name='r0')
        self.n0 = (SpatialNoise(name='n0', noise_rate=self.noise_rate,
                tied_noise=tied_noise, tied_sigma=tied_sigma,
                prior_noise_level=prior_noise_level) if mid_noise else None)
        self.c0 = Convolutional(name='c0')
        self.b1 = SpatialBatchNormalization(name='b1')
        self.r1 = Rectifier(name='r1')
        self.n1 = (SpatialNoise(name='n1', noise_rate=self.noise_rate,
                tied_noise=tied_noise, tied_sigma=tied_sigma,
                prior_noise_level=prior_noise_level) if out_noise else None)
        self.c1 = Convolutional(name='c1')
        kwargs.setdefault('children', []).extend([c for c in [
            self.c0, self.b0, self.r0, self.n0,
            self.c1, self.b1, self.r1, self.n1] if c is not None])
        super(ResidualConvolutional, self).__init__(**kwargs)

    def get_dim(self, name):
        if name == 'input_':
            return ((self.num_channels,) + self.image_size)
        if name == 'output':
            return self.c1.get_dim(name)
        return super(ResidualConvolutionalUnit, self).get_dim(name)

    @property
    def num_output_channels(self):
        return self.num_filters

    def _push_allocation_config(self):
        self.b0.input_dim = self.get_dim('input_')
        self.b0.push_allocation_config()
        if self.r0:
            self.r0.push_allocation_config()
        if self.n0:
            self.n0.noise_batch_size = self.noise_batch_size
            self.n0.num_channels = self.num_channels
            self.n0.image_size = self.image_size
        self.c0.filter_size = self.filter_size
        self.c0.batch_size = self.batch_size
        self.c0.num_channels = self.num_channels
        self.c0.num_filters = self.num_filters
        self.c0.border_mode = self.border_mode
        self.c0.image_size = self.image_size
        self.c0.step = self.step
        self.c0.use_bias = False
        self.c0.push_allocation_config()
        c0_shape = self.c0.get_dim('output')
        self.b1.input_dim = c0_shape
        self.b1.push_allocation_config()
        self.r1.push_allocation_config()
        if self.n1:
            self.n1.noise_batch_size = self.noise_batch_size
            self.n1.num_channels = self.num_filters
            self.n1.image_size = c0_shape[1:]
        self.c1.filter_size = self.filter_size
        self.c1.batch_size = self.batch_size
        self.c1.num_channels = self.num_filters
        self.c1.num_filters = self.num_filters
        self.c1.border_mode = self.border_mode
        self.c1.image_size = c0_shape[1:]
        self.c1.step = (1, 1)
        self.c1.use_bias = False
        self.c1.push_allocation_config()

    @application(inputs=['input_'], outputs=['output'])
    def apply(self, input_):
        shortcut = input_
        # Batchnorm, then Relu, then Convolution
        first_conv = self.b0.apply(input_)
        first_conv = self.r0.apply(first_conv)
        if self.n0:
            first_conv = self.n0.apply(first_conv)
        first_conv = self.c0.apply(first_conv)
        # Batchnorm, then Relu, then Convolution (second time)
        second_conv = self.b1.apply(first_conv)
        second_conv = self.r1.apply(second_conv)
        if self.n1:
            second_conv = self.n1.apply(second_conv)
        residual = second_conv

        # Apply stride and zero-padding to match shortcut to output
        if self.step and self.step != (1, 1):
            shortcut = shortcut[:,:,::self.step[0],::self.step[1]]
        if self.num_filters > self.num_channels:
            padshape = (residual.shape[0],
                    self.num_filters - self.num_channels,
                    residual.shape[2], residual.shape[3])
            shortcut = tensor.concatenate(
                    [shortcut, tensor.zeros(padshape, dtype=residual.dtype)],
                    axis=1)
        elif self.num_filters < self.num_channels:
            shortcut = shortcut[:,:self.num_channels,:,:]

        response = shortcut + residual
        return response
Exemple #12
0
class NoisyConvolutional(Initializable, Feedforward, Random):
    """Convolutional transformation sent through a learned noisy channel.

    Parameters (same as Convolutional)
    """
    @lazy(allocation=[
        'filter_size', 'num_filters', 'num_channels', 'noise_batch_size'
    ])
    def __init__(self,
                 filter_size,
                 num_filters,
                 num_channels,
                 noise_batch_size,
                 image_size=(None, None),
                 step=(1, 1),
                 border_mode='valid',
                 tied_biases=True,
                 prior_mean=0,
                 prior_noise_level=0,
                 **kwargs):
        self.convolution = Convolutional()
        self.mask = Convolutional(name='mask')
        children = [self.convolution, self.mask]
        kwargs.setdefault('children', []).extend(children)
        super(NoisyConvolutional, self).__init__(**kwargs)
        self.filter_size = filter_size
        self.num_filters = num_filters
        self.num_channels = num_channels
        self.noise_batch_size = noise_batch_size
        self.image_size = image_size
        self.step = step
        self.border_mode = border_mode
        self.tied_biases = tied_biases
        self.prior_mean = prior_mean
        self.prior_noise_level = prior_noise_level

    def _push_allocation_config(self):
        self.convolution.filter_size = self.filter_size
        self.convolution.num_filters = self.num_filters
        self.convolution.num_channels = self.num_channels
        # self.convolution.batch_size = self.batch_size
        self.convolution.image_size = self.image_size
        self.convolution.step = self.step
        self.convolution.border_mode = self.border_mode
        self.convolution.tied_biases = self.tied_biases
        self.mask.filter_size = (1, 1)
        self.mask.num_filters = self.num_filters
        self.mask.num_channels = self.num_filters
        # self.mask.batch_size = self.batch_size
        self.mask.image_size = self.convolution.get_dim('output')[1:]
        # self.mask.step = self.step
        # self.mask.border_mode = self.border_mode
        self.mask.tied_biases = self.tied_biases

    def _allocate(self):
        out_shape = self.convolution.get_dim('output')
        N = shared_floatx_zeros((self.noise_batch_size, ) + out_shape,
                                name='N')
        add_role(N, NOISE)
        self.parameters.append(N)

    @application(inputs=['input_'], outputs=['output'])
    def apply(self, input_, application_call):
        """Apply the linear transformation followed by masking with noise.
        Parameters
        ----------
        input_ : :class:`~tensor.TensorVariable`
            The input on which to apply the transformations
        Returns
        -------
        output : :class:`~tensor.TensorVariable`
            The transformed input
        """
        from theano.printing import Print

        pre_noise = self.convolution.apply(input_)
        # noise_level = self.mask.apply(input_)
        noise_level = (self.prior_noise_level -
                       tensor.clip(self.mask.apply(pre_noise), -16, 16))
        noise_level = copy_and_tag_noise(noise_level, self, LOG_SIGMA,
                                         'log_sigma')
        # Allow incomplete batches by just taking the noise that is needed
        noise = self.parameters[0][:noise_level.shape[0], :, :, :]
        # noise = self.theano_rng.normal(noise_level.shape)
        kl = (self.prior_noise_level - noise_level + 0.5 *
              (tensor.exp(2 * noise_level) +
               (pre_noise - self.prior_mean)**2) /
              tensor.exp(2 * self.prior_noise_level) - 0.5)
        application_call.add_auxiliary_variable(kl, roles=[NITS], name='nits')
        return pre_noise + tensor.exp(noise_level) * noise

    def get_dim(self, name):
        if name == 'input_':
            return self.convolution.get_dim(name)
        if name == 'output':
            return self.convolution.get_dim(name)
        if name == 'nits':
            return self.convolution.get_dim('output')
        return super(NoisyConvolutional, self).get_dim(name)

    @property
    def num_output_channels(self):
        return self.num_filters
Exemple #13
0
class ResidualConvolutional(Initializable):
    @lazy(allocation=['filter_size', 'num_filters', 'num_channels'])
    def __init__(self,
                 filter_size,
                 num_filters,
                 num_channels,
                 batch_size=None,
                 mid_noise=False,
                 out_noise=False,
                 tied_noise=False,
                 tied_sigma=False,
                 noise_rate=None,
                 noise_batch_size=None,
                 prior_noise_level=None,
                 image_size=(None, None),
                 step=(1, 1),
                 **kwargs):
        self.filter_size = filter_size
        self.num_filters = num_filters
        self.batch_size = batch_size
        self.num_channels = num_channels
        self.image_size = image_size
        self.mid_noise = mid_noise
        self.noise_batch_size = noise_batch_size
        self.noise_rate = noise_rate
        self.step = step
        self.border_mode = 'half'
        self.tied_biases = True
        depth = 2

        self.b0 = SpatialBatchNormalization(name='b0')
        self.r0 = Rectifier(name='r0')
        self.n0 = (SpatialNoise(name='n0',
                                noise_rate=self.noise_rate,
                                tied_noise=tied_noise,
                                tied_sigma=tied_sigma,
                                prior_noise_level=prior_noise_level)
                   if mid_noise else None)
        self.c0 = Convolutional(name='c0')
        self.b1 = SpatialBatchNormalization(name='b1')
        self.r1 = Rectifier(name='r1')
        self.n1 = (SpatialNoise(name='n1',
                                noise_rate=self.noise_rate,
                                tied_noise=tied_noise,
                                tied_sigma=tied_sigma,
                                prior_noise_level=prior_noise_level)
                   if out_noise else None)
        self.c1 = Convolutional(name='c1')
        kwargs.setdefault('children', []).extend([
            c for c in [
                self.c0, self.b0, self.r0, self.n0, self.c1, self.b1, self.r1,
                self.n1
            ] if c is not None
        ])
        super(ResidualConvolutional, self).__init__(**kwargs)

    def get_dim(self, name):
        if name == 'input_':
            return ((self.num_channels, ) + self.image_size)
        if name == 'output':
            return self.c1.get_dim(name)
        return super(ResidualConvolutionalUnit, self).get_dim(name)

    @property
    def num_output_channels(self):
        return self.num_filters

    def _push_allocation_config(self):
        self.b0.input_dim = self.get_dim('input_')
        self.b0.push_allocation_config()
        if self.r0:
            self.r0.push_allocation_config()
        if self.n0:
            self.n0.noise_batch_size = self.noise_batch_size
            self.n0.num_channels = self.num_channels
            self.n0.image_size = self.image_size
        self.c0.filter_size = self.filter_size
        self.c0.batch_size = self.batch_size
        self.c0.num_channels = self.num_channels
        self.c0.num_filters = self.num_filters
        self.c0.border_mode = self.border_mode
        self.c0.image_size = self.image_size
        self.c0.step = self.step
        self.c0.use_bias = False
        self.c0.push_allocation_config()
        c0_shape = self.c0.get_dim('output')
        self.b1.input_dim = c0_shape
        self.b1.push_allocation_config()
        self.r1.push_allocation_config()
        if self.n1:
            self.n1.noise_batch_size = self.noise_batch_size
            self.n1.num_channels = self.num_filters
            self.n1.image_size = c0_shape[1:]
        self.c1.filter_size = self.filter_size
        self.c1.batch_size = self.batch_size
        self.c1.num_channels = self.num_filters
        self.c1.num_filters = self.num_filters
        self.c1.border_mode = self.border_mode
        self.c1.image_size = c0_shape[1:]
        self.c1.step = (1, 1)
        self.c1.use_bias = False
        self.c1.push_allocation_config()

    @application(inputs=['input_'], outputs=['output'])
    def apply(self, input_):
        shortcut = input_
        # Batchnorm, then Relu, then Convolution
        first_conv = self.b0.apply(input_)
        first_conv = self.r0.apply(first_conv)
        if self.n0:
            first_conv = self.n0.apply(first_conv)
        first_conv = self.c0.apply(first_conv)
        # Batchnorm, then Relu, then Convolution (second time)
        second_conv = self.b1.apply(first_conv)
        second_conv = self.r1.apply(second_conv)
        if self.n1:
            second_conv = self.n1.apply(second_conv)
        residual = second_conv

        # Apply stride and zero-padding to match shortcut to output
        if self.step and self.step != (1, 1):
            shortcut = shortcut[:, :, ::self.step[0], ::self.step[1]]
        if self.num_filters > self.num_channels:
            padshape = (residual.shape[0],
                        self.num_filters - self.num_channels,
                        residual.shape[2], residual.shape[3])
            shortcut = tensor.concatenate(
                [shortcut,
                 tensor.zeros(padshape, dtype=residual.dtype)],
                axis=1)
        elif self.num_filters < self.num_channels:
            shortcut = shortcut[:, :self.num_channels, :, :]

        response = shortcut + residual
        return response
Exemple #14
0
o = X.reshape((X.shape[0], 1, 28, 28))

l = Convolutional(filter_size=(5, 5),
        num_filters=32,
        num_channels=1,
        image_size=(28,28),
        weights_init=IsotropicGaussian(std=0.01),
        biases_init=IsotropicGaussian(std=0.01, mean=1.0),
        use_bias=True,
        border_mode="valid",
        step=(1,1))
l.initialize()
o = l.apply(o)

l = BatchNormalizationConv(input_shape=l.get_dim("output"),
        B_init=IsotropicGaussian(std=0.01),
        Y_init=IsotropicGaussian(std=0.01))
l.initialize()
o = l.apply(o)

o = Rectifier().apply(o)

l = MaxPooling(pooling_size=(2, 2),
        step=(2, 2),
        input_dim=l.get_dim("output"))
l.initialize()
o = l.apply(o)

#ll = Dropout(p_drop=0.5)
#ll.initialize()
Exemple #15
0
class NoisyConvolutional(Initializable, Feedforward, Random):
    """Convolutional transformation sent through a learned noisy channel.

    Parameters (same as Convolutional)
    """
    @lazy(allocation=[
        'filter_size', 'num_filters', 'num_channels', 'noise_batch_size'])
    def __init__(self, filter_size, num_filters, num_channels, noise_batch_size,
                 image_size=(None, None), step=(1, 1), border_mode='valid',
                 tied_biases=True,
                 prior_mean=0, prior_noise_level=0, **kwargs):
        self.convolution = Convolutional()
        self.mask = Convolutional(name='mask')
        children = [self.convolution, self.mask]
        kwargs.setdefault('children', []).extend(children)
        super(NoisyConvolutional, self).__init__(**kwargs)
        self.filter_size = filter_size
        self.num_filters = num_filters
        self.num_channels = num_channels
        self.noise_batch_size = noise_batch_size
        self.image_size = image_size
        self.step = step
        self.border_mode = border_mode
        self.tied_biases = tied_biases
        self.prior_mean = prior_mean
        self.prior_noise_level = prior_noise_level

    def _push_allocation_config(self):
        self.convolution.filter_size = self.filter_size
        self.convolution.num_filters = self.num_filters
        self.convolution.num_channels = self.num_channels
        # self.convolution.batch_size = self.batch_size
        self.convolution.image_size = self.image_size
        self.convolution.step = self.step
        self.convolution.border_mode = self.border_mode
        self.convolution.tied_biases = self.tied_biases
        self.mask.filter_size = (1, 1)
        self.mask.num_filters = self.num_filters
        self.mask.num_channels = self.num_filters
        # self.mask.batch_size = self.batch_size
        self.mask.image_size = self.convolution.get_dim('output')[1:]
        # self.mask.step = self.step
        # self.mask.border_mode = self.border_mode
        self.mask.tied_biases = self.tied_biases

    def _allocate(self):
        out_shape = self.convolution.get_dim('output')
        N = shared_floatx_zeros((self.noise_batch_size,) + out_shape, name='N')
        add_role(N, NOISE)
        self.parameters.append(N)

    @application(inputs=['input_'], outputs=['output'])
    def apply(self, input_, application_call):
        """Apply the linear transformation followed by masking with noise.
        Parameters
        ----------
        input_ : :class:`~tensor.TensorVariable`
            The input on which to apply the transformations
        Returns
        -------
        output : :class:`~tensor.TensorVariable`
            The transformed input
        """
        from theano.printing import Print

        pre_noise = self.convolution.apply(input_)
        # noise_level = self.mask.apply(input_)
        noise_level = (self.prior_noise_level -
                tensor.clip(self.mask.apply(pre_noise), -16, 16))
        noise_level = copy_and_tag_noise(
                noise_level, self, LOG_SIGMA, 'log_sigma')
        # Allow incomplete batches by just taking the noise that is needed
        noise = self.parameters[0][:noise_level.shape[0], :, :, :]
        # noise = self.theano_rng.normal(noise_level.shape)
        kl = (
            self.prior_noise_level - noise_level 
            + 0.5 * (
                tensor.exp(2 * noise_level)
                + (pre_noise - self.prior_mean) ** 2
                ) / tensor.exp(2 * self.prior_noise_level)
            - 0.5
            )
        application_call.add_auxiliary_variable(kl, roles=[NITS], name='nits')
        return pre_noise + tensor.exp(noise_level) * noise

    def get_dim(self, name):
        if name == 'input_':
            return self.convolution.get_dim(name)
        if name == 'output':
            return self.convolution.get_dim(name)
        if name == 'nits':
            return self.convolution.get_dim('output')
        return super(NoisyConvolutional, self).get_dim(name)

    @property
    def num_output_channels(self):
        return self.num_filters