diff --git a/keras_contrib/layers/convolutional.py b/keras_contrib/layers/convolutional.py index 307b5e4..dedc0f6 100644 --- a/keras_contrib/layers/convolutional.py +++ b/keras_contrib/layers/convolutional.py @@ -157,6 +157,7 @@ class Deconvolution3D(Convolution3D): - [Transposed convolution arithmetic](http://deeplearning.net/software/theano_versions/dev/tutorial/conv_arithmetic.html#transposed-convolution-arithmetic) - [Deconvolutional Networks](http://www.matthewzeiler.com/pubs/cvpr2010/cvpr2010.pdf) """ + def __init__(self, nb_filter, kernel_dim1, kernel_dim2, kernel_dim3, output_shape, init='glorot_uniform', activation=None, weights=None, border_mode='valid', subsample=(1, 1, 1), @@ -225,6 +226,7 @@ class Deconvolution3D(Convolution3D): base_config = super(Deconvolution3D, self).get_config() return dict(list(base_config.items()) + list(config.items())) + Deconv3D = Deconvolution3D get_custom_objects().update({"Deconvolution3D": Deconvolution3D}) get_custom_objects().update({"Deconv3D": Deconv3D}) @@ -409,9 +411,9 @@ class CosineConvolution2D(Layer): Wnorm = K.sqrt(K.sum(K.square(self.W), axis=W_sum_axes, keepdims=True) + K.square(b) + K.epsilon()) xnorm = K.sqrt(K.conv2d(K.square(x), self.W_norm, strides=self.subsample, - border_mode=self.border_mode, - dim_ordering=self.dim_ordering, - filter_shape=self.W_norm_shape) + xb + K.epsilon()) + border_mode=self.border_mode, + dim_ordering=self.dim_ordering, + filter_shape=self.W_norm_shape) + xb + K.epsilon()) W = self.W / Wnorm @@ -456,12 +458,66 @@ class CosineConvolution2D(Layer): base_config = super(CosineConvolution2D, self).get_config() return dict(list(base_config.items()) + list(config.items())) + CosineConv2D = CosineConvolution2D get_custom_objects().update({"CosineConvolution2D": CosineConvolution2D}) get_custom_objects().update({"CosineConv2D": CosineConv2D}) class SubPixelUpscaling(Layer): + """ Sub-pixel convolutional upscaling layer based on the paper "Real-Time Single Image + and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network" + (https://arxiv.org/abs/1609.05158). + + This layer requires a Convolution2D prior to it, having output nb_filter computed accordomg to + the formula : + + nb_filter = k * (scale_factor * scale_factor) + where k = a user defined number of filters (generally larger than 32) + scale_factor = the upscaling factor (generally 2) + + This layer performs the depth to space operation on the convolution filters, and returns a + tensor with the size as defined below. + + # Note: + This layer does not work with mismatched backend and dim ordering. + For example, TH dim ordering with Tensorflow backend / TF dim ordering with Theano backend. + + # Example : + ```python + # A standard subpixel upscaling block + x = Convolution2D(256, 3, 3, border_mode='same', activation='relu')(...) + u = SubPixelUpscaling(scale_factor=2)(x) + + [Optional] + x = Convolution2D(256, 3, 3, border_mode='same', activation='relu')(u) + ``` + + In practice, it is useful to have a second convolution layer after the + SubPixelUpscaling layer to speed up the learning process. + + However, if you are stacking multiple SubPixelUpscaling blocks, it may increase + the number of parameters greatly, so the Convolution layer after SubPixelUpscaling + layer can be removed. + + # Arguments + scale_factor: Upscaling factor. + dim_ordering: Can be 'th' or 'tf'. Note: mismatched dim ordering will + cause a ValueError to be raised. + + # Input shape + 4D tensor with shape: + `(samples, k * (scale_factor * scale_factor) channels, rows, cols)` if dim_ordering='th' + or 4D tensor with shape: + `(samples, rows, cols, k * (scale_factor * scale_factor) channels)` if dim_ordering='tf'. + + # Output shape + 4D tensor with shape: + `(samples, k channels, rows * scale_factor, cols * scale_factor))` if dim_ordering='th' + or 4D tensor with shape: + `(samples, rows * scale_factor, cols * scale_factor, k channels)` if dim_ordering='tf'. + + """ def __init__(self, scale_factor=2, dim_ordering='default', **kwargs): super(SubPixelUpscaling, self).__init__(**kwargs) @@ -472,6 +528,11 @@ class SubPixelUpscaling(Layer): if self.dim_ordering == 'default': self.dim_ordering = K.image_dim_ordering() + if (K.backend() == 'theano' and self.dim_ordering == 'tf') or \ + (K.backend() == 'tensorflow' and self.dim_ordering == 'th'): + raise ValueError('SubPixelUpscaling cannot be used with mismatched backend / dim ordering combinations. ' + 'Backend : %s, Dim Ordering : %s' % (K.backend(), self.dim_ordering)) + def build(self, input_shape): pass @@ -493,4 +554,5 @@ class SubPixelUpscaling(Layer): base_config = super(SubPixelUpscaling, self).get_config() return dict(list(base_config.items()) + list(config.items())) + get_custom_objects().update({'SubPixelUpscaling': SubPixelUpscaling})