mirror of
https://github.com/wassname/keras-contrib.git
synced 2026-07-18 12:30:55 +08:00
230 lines
11 KiB
Python
230 lines
11 KiB
Python
# -*- coding: utf-8 -*-
|
|
from __future__ import absolute_import
|
|
import functools
|
|
|
|
from .. import backend as K
|
|
from .. import activations
|
|
from .. import initializations
|
|
from .. import regularizers
|
|
from .. import constraints
|
|
from keras.engine import Layer
|
|
from keras.engine import InputSpec
|
|
from keras.layers.convolutional import Convolution3D
|
|
from keras.utils.generic_utils import get_custom_objects
|
|
from keras.utils.np_utils import conv_output_length
|
|
from keras.utils.np_utils import conv_input_length
|
|
|
|
|
|
class Deconvolution3D(Convolution3D):
|
|
"""Transposed convolution operator for filtering windows of 3-D inputs.
|
|
|
|
The need for transposed convolutions generally arises from the desire to
|
|
use a transformation going in the opposite direction
|
|
of a normal convolution, i.e., from something that has the shape
|
|
of the output of some convolution to something that has the shape
|
|
of its input while maintaining a connectivity pattern
|
|
that is compatible with said convolution.
|
|
|
|
When using this layer as the first layer in a model,
|
|
provide the keyword argument `input_shape`
|
|
(tuple of integers, does not include the sample axis),
|
|
e.g. `input_shape=(3, 128, 128, 128)` for a 128x128x128 volume with
|
|
three channels.
|
|
|
|
To pass the correct `output_shape` to this layer,
|
|
one could use a test model to predict and observe the actual output shape.
|
|
|
|
# Examples
|
|
|
|
```python
|
|
# TH dim ordering.
|
|
# apply a 3x3x3 transposed convolution
|
|
# with stride 1x1x1 and 3 output filters on a 12x12x12 image:
|
|
model = Sequential()
|
|
model.add(Deconvolution3D(3, 3, 3, 3, output_shape=(None, 3, 14, 14, 14),
|
|
border_mode='valid',
|
|
input_shape=(3, 12, 12, 12)))
|
|
|
|
# we can predict with the model and print the shape of the array.
|
|
dummy_input = np.ones((32, 3, 12, 12, 12))
|
|
preds = model.predict(dummy_input)
|
|
print(preds.shape) # (None, 3, 14, 14, 14)
|
|
|
|
# apply a 3x3x3 transposed convolution
|
|
# with stride 2x2x2 and 3 output filters on a 12x12x12 image:
|
|
model = Sequential()
|
|
model.add(Deconvolution3D(3, 3, 3, 3, output_shape=(None, 3, 25, 25, 25),
|
|
subsample=(2, 2, 2),
|
|
border_mode='valid',
|
|
input_shape=(3, 12, 12, 12)))
|
|
model.summary()
|
|
|
|
# we can predict with the model and print the shape of the array.
|
|
dummy_input = np.ones((32, 3, 12, 12, 12))
|
|
preds = model.predict(dummy_input)
|
|
print(preds.shape) # (None, 3, 25, 25, 25)
|
|
```
|
|
|
|
```python
|
|
# TF dim ordering.
|
|
# apply a 3x3x3 transposed convolution
|
|
# with stride 1x1x1 and 3 output filters on a 12x12x12 image:
|
|
model = Sequential()
|
|
model.add(Deconvolution3D(3, 3, 3, 3, output_shape=(None, 14, 14, 14, 3),
|
|
border_mode='valid',
|
|
input_shape=(12, 12, 12, 3)))
|
|
|
|
# we can predict with the model and print the shape of the array.
|
|
dummy_input = np.ones((32, 12, 12, 12, 3))
|
|
preds = model.predict(dummy_input)
|
|
print(preds.shape) # (None, 14, 14, 14, 3)
|
|
|
|
# apply a 3x3x3 transposed convolution
|
|
# with stride 2x2x2 and 3 output filters on a 12x12x12 image:
|
|
model = Sequential()
|
|
model.add(Deconvolution3D(3, 3, 3, 3, output_shape=(None, 25, 25, 25, 3),
|
|
subsample=(2, 2, 2),
|
|
border_mode='valid',
|
|
input_shape=(12, 12, 12, 3)))
|
|
model.summary()
|
|
|
|
# we can predict with the model and print the shape of the array.
|
|
dummy_input = np.ones((32, 12, 12, 12, 3))
|
|
preds = model.predict(dummy_input)
|
|
print(preds.shape) # (None, 25, 25, 25, 3)
|
|
```
|
|
|
|
# Arguments
|
|
nb_filter: Number of transposed convolution filters to use.
|
|
kernel_dim1: Length of the first dimension in the transposed convolution kernel.
|
|
kernel_dim2: Length of the second dimension in the transposed convolution kernel.
|
|
kernel_dim3: Length of the third dimension in the transposed convolution kernel.
|
|
output_shape: Output shape of the transposed convolution operation.
|
|
tuple of integers
|
|
`(nb_samples, nb_filter, conv_dim1, conv_dim2, conv_dim3)`.
|
|
It is better to use
|
|
a dummy input and observe the actual output shape of
|
|
a layer, as specified in the examples.
|
|
init: name of initialization function for the weights of the layer
|
|
(see [initializations](../initializations.md)), or alternatively,
|
|
Theano function to use for weights initialization.
|
|
This parameter is only relevant if you don't pass
|
|
a `weights` argument.
|
|
activation: name of activation function to use
|
|
(see [activations](../activations.md)),
|
|
or alternatively, elementwise Theano/TensorFlow function.
|
|
If you don't specify anything, no activation is applied
|
|
(ie. "linear" activation: a(x) = x).
|
|
weights: list of numpy arrays to set as initial weights.
|
|
border_mode: 'valid', 'same' or 'full'
|
|
('full' requires the Theano backend).
|
|
subsample: tuple of length 3. Factor by which to oversample output.
|
|
Also called strides elsewhere.
|
|
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
|
(eg. L1 or L2 regularization), applied to the main weights matrix.
|
|
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
|
applied to the bias.
|
|
activity_regularizer: instance of [ActivityRegularizer](../regularizers.md),
|
|
applied to the network output.
|
|
W_constraint: instance of the [constraints](../constraints.md) module
|
|
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
|
b_constraint: instance of the [constraints](../constraints.md) module,
|
|
applied to the bias.
|
|
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
|
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
|
It defaults to the `image_dim_ordering` value found in your
|
|
Keras config file at `~/.keras/keras.json`.
|
|
If you never set it, then it will be "tf".
|
|
bias: whether to include a bias
|
|
(i.e. make the layer affine rather than linear).
|
|
|
|
# Input shape
|
|
5D tensor with shape:
|
|
`(samples, channels, conv_dim1, conv_dim2, conv_dim3)` if dim_ordering='th'
|
|
or 5D tensor with shape:
|
|
`(samples, conv_dim1, conv_dim2, conv_dim3, channels)` if dim_ordering='tf'.
|
|
|
|
# Output shape
|
|
5D tensor with shape:
|
|
`(samples, nb_filter, new_conv_dim1, new_conv_dim2, new_conv_dim3)` if dim_ordering='th'
|
|
or 5D tensor with shape:
|
|
`(samples, new_conv_dim1, new_conv_dim2, new_conv_dim3, nb_filter)` if dim_ordering='tf'.
|
|
`new_conv_dim1`, `new_conv_dim2` and `new_conv_dim3` values might have changed due to padding.
|
|
|
|
# References
|
|
- [A guide to convolution arithmetic for deep learning](https://arxiv.org/abs/1603.07285v1)
|
|
- [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),
|
|
dim_ordering='default',
|
|
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
|
W_constraint=None, b_constraint=None,
|
|
bias=True, **kwargs):
|
|
if dim_ordering == 'default':
|
|
dim_ordering = K.image_dim_ordering()
|
|
if border_mode not in {'valid', 'same', 'full'}:
|
|
raise ValueError('Invalid border mode for Deconvolution3D:', border_mode)
|
|
if len(output_shape) == 4:
|
|
# missing the batch size
|
|
output_shape = (None,) + tuple(output_shape)
|
|
|
|
self.output_shape_ = output_shape
|
|
|
|
super(Deconvolution3D, self).__init__(nb_filter,
|
|
kernel_dim1, kernel_dim2, kernel_dim3,
|
|
init=init,
|
|
activation=activation,
|
|
weights=weights,
|
|
border_mode=border_mode,
|
|
subsample=subsample,
|
|
dim_ordering=dim_ordering,
|
|
W_regularizer=W_regularizer,
|
|
b_regularizer=b_regularizer,
|
|
activity_regularizer=activity_regularizer,
|
|
W_constraint=W_constraint,
|
|
b_constraint=b_constraint,
|
|
bias=bias,
|
|
**kwargs)
|
|
|
|
def get_output_shape_for(self, input_shape):
|
|
if self.dim_ordering == 'th':
|
|
conv_dim1 = self.output_shape_[2]
|
|
conv_dim2 = self.output_shape_[3]
|
|
conv_dim3 = self.output_shape_[4]
|
|
return (input_shape[0], self.nb_filter, conv_dim1, conv_dim2, conv_dim3)
|
|
elif self.dim_ordering == 'tf':
|
|
conv_dim1 = self.output_shape_[1]
|
|
conv_dim2 = self.output_shape_[2]
|
|
conv_dim3 = self.output_shape_[3]
|
|
return (input_shape[0], conv_dim1, conv_dim2, conv_dim3, self.nb_filter)
|
|
else:
|
|
raise ValueError('Invalid dim_ordering:', self.dim_ordering)
|
|
|
|
def call(self, x, mask=None):
|
|
output = K.deconv3d(x, self.W, self.output_shape_,
|
|
strides=self.subsample,
|
|
border_mode=self.border_mode,
|
|
dim_ordering=self.dim_ordering,
|
|
filter_shape=self.W_shape)
|
|
if self.bias:
|
|
if self.dim_ordering == 'th':
|
|
output += K.reshape(self.b, (1, self.nb_filter, 1, 1, 1))
|
|
elif self.dim_ordering == 'tf':
|
|
output += K.reshape(self.b, (1, 1, 1, 1, self.nb_filter))
|
|
else:
|
|
raise ValueError('Invalid dim_ordering:', self.dim_ordering)
|
|
output = self.activation(output)
|
|
return output
|
|
|
|
def get_config(self):
|
|
config = {'output_shape': self.output_shape_}
|
|
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})
|