Skip to content

Commit

Permalink
Merge pull request #968 from dwf/activations_in_conv_seq
Browse files Browse the repository at this point in the history
Allow elementwise Activations inside ConvolutionalSequence.
  • Loading branch information
dwf committed Feb 1, 2016
2 parents 2131a0c + 2183267 commit a302e70
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
21 changes: 17 additions & 4 deletions blocks/bricks/conv.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
from theano import tensor
from theano.tensor.nnet import conv2d
from theano.tensor.nnet.abstract_conv import (AbstractConv2d_gradInputs,
get_conv_output_shape)
from theano.tensor.signal.pool import pool_2d, Pool

from blocks.bricks import Initializable, Feedforward, Sequence
from blocks.bricks import Initializable, Feedforward, Sequence, Activation
from blocks.bricks.base import application, Brick, lazy
from blocks.roles import add_role, FILTER, BIAS
from blocks.utils import shared_floatx_nans
Expand Down Expand Up @@ -496,6 +495,8 @@ class ConvolutionalSequence(Sequence, Initializable, Feedforward):
layers : list
List of convolutional bricks (i.e. :class:`Convolutional`,
:class:`ConvolutionalActivation`, or :class:`Pooling` bricks).
:class:`Activation` bricks that operate elementwise can also
be included.
num_channels : int
Number of input channels in the image. For the first layer this is
normally 1 for grayscale images and 3 for color (RGB) images. For
Expand Down Expand Up @@ -553,13 +554,25 @@ def get_dim(self, name):
if name == 'input_':
return ((self.num_channels,) + self.image_size)
if name == 'output':
return self.layers[-1].get_dim(name)
last = len(self.layers) - 1
while last >= 0:
try:
return self.layers[last].get_dim(name)
except ValueError:
last -= 1
# The output shape of an empty ConvolutionalSequence or one
# consisting only of Activations is the input shape.
return self.get_dim('input_')
return super(ConvolutionalSequence, self).get_dim(name)

def _push_allocation_config(self):
num_channels = self.num_channels
image_size = self.image_size
for layer in self.layers:
if isinstance(layer, Activation):
# Activations operate elementwise; nothing to set.
layer.push_allocation_config()
continue
if self.border_mode is not None:
layer.border_mode = self.border_mode
layer.tied_biases = self.tied_biases
Expand All @@ -569,7 +582,7 @@ def _push_allocation_config(self):
layer.use_bias = self.use_bias

# Push input dimensions to children
layer._push_allocation_config()
layer.push_allocation_config()

# Retrieve output dimensions
# and set it for next layer
Expand Down
3 changes: 2 additions & 1 deletion blocks/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ def shared_floatx_zeros_matching(shared_variable, name=None, **kwargs):
name : :obj:`str`, optional
The name for the shared variable. Defaults to `None`.
\*\*kwargs
Keyword arguments to pass to the :func:`shared_floatx_zeros` function.
Keyword arguments to pass to the :func:`shared_floatx_zeros`
function.
Returns
-------
Expand Down
39 changes: 39 additions & 0 deletions tests/bricks/test_conv.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,45 @@ def test_convolutional_sequence():
assert_allclose(func(x_val), y_val)


def test_convolutional_sequence_with_raw_activation():
seq = ConvolutionalSequence([Rectifier()], num_channels=4,
image_size=(20, 14))
input_ = (((numpy.arange(2 * 4 * 20 * 14)
.reshape((2, 4, 20, 14)) % 2) * 2 - 1)
.astype(theano.config.floatX))
expected_ = input_ * (input_ > 0)
x = theano.tensor.tensor4()
assert_allclose(seq.apply(x).eval({x: input_}), expected_)


def test_convolutional_sequence_with_convolutions_raw_activation():
seq = ConvolutionalSequence(
[Convolutional(filter_size=(3, 3), num_filters=4),
Rectifier(),
Convolutional(filter_size=(5, 5), num_filters=3, step=(2, 2)),
Tanh()],
num_channels=2,
image_size=(21, 39))
seq.allocate()
x = theano.tensor.tensor4()
out = seq.apply(x).eval({x: numpy.ones((10, 2, 21, 39),
dtype=theano.config.floatX)})
assert out.shape == (10, 3, 8, 17)


def test_convolutional_sequence_activation_get_dim():
seq = ConvolutionalSequence([Tanh()], num_channels=9, image_size=(4, 6))
seq.allocate()
assert seq.get_dim('output') == (9, 4, 6)

seq = ConvolutionalSequence([Convolutional(filter_size=(7, 7),
num_filters=5,
border_mode=(1, 1)),
Tanh()], num_channels=8, image_size=(8, 11))
seq.allocate()
assert seq.get_dim('output') == (5, 4, 7)


def test_convolutional_activation_use_bias():
act = ConvolutionalActivation(Rectifier().apply, (3, 3), 5, 4,
image_size=(9, 9), use_bias=False)
Expand Down

0 comments on commit a302e70

Please sign in to comment.