diff --git a/docs/modules/layers.rst b/docs/modules/layers.rst index 829086bf3..d34597c1f 100644 --- a/docs/modules/layers.rst +++ b/docs/modules/layers.rst @@ -270,6 +270,9 @@ Layer list Conv2d DeConv2d DeConv3d + DepthwiseConv2d + DeformableConv2d + GroupConv2d MaxPool1d MeanPool1d @@ -278,9 +281,6 @@ Layer list MaxPool3d MeanPool3d - DepthwiseConv2d - DeformableConv2d - SubpixelConv1d SubpixelConv2d @@ -496,6 +496,9 @@ APIs may better for you. ^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: DeformableConv2d +2D Grouped Conv +^^^^^^^^^^^^^^^^^^^^^^^ +.. autoclass:: GroupConv2d Super-Resolution layer ------------------------ diff --git a/tensorlayer/layers/convolution.py b/tensorlayer/layers/convolution.py index 3697de4fb..9aff47fb5 100644 --- a/tensorlayer/layers/convolution.py +++ b/tensorlayer/layers/convolution.py @@ -1647,6 +1647,87 @@ def __init__( self.all_params.extend([W]) +class GroupConv2d(Layer): + """The :class:`GroupConv2d` class is 2D grouped convolution, see `here `__. + + Parameters + -------------- + layer : :class:`Layer` + Previous layer. + n_filter : int + The number of filters. + filter_size : int + The filter size. + stride : int + The stride step. + n_group : int + The number of groups. + act : activation function + The activation function of this layer. + padding : str + The padding algorithm type: "SAME" or "VALID". + W_init : initializer + The initializer for the weight matrix. + b_init : initializer or None + The initializer for the bias vector. If None, skip biases. + W_init_args : dictionary + The arguments for the weight matrix initializer. + b_init_args : dictionary + The arguments for the bias vector initializer. + name : str + A unique layer name. + """ + + def __init__( + self, + layer=None, + n_filter=32, + filter_size=(3, 3), + strides=(2, 2), + n_group=2, + act=tf.identity, + padding='SAME', + W_init=tf.truncated_normal_initializer(stddev=0.02), + b_init=tf.constant_initializer(value=0.0), + W_init_args=None, + b_init_args=None, + name='groupconv', + ): # Windaway + if W_init_args is None: + W_init_args = {} + if b_init_args is None: + b_init_args = {} + + Layer.__init__(self, name=name) + self.inputs = layer.outputs + groupConv = lambda i, k: tf.nn.conv2d(i, k, strides=[1, strides[0], strides[1], 1], padding=padding) + channels = int(self.inputs.get_shape()[-1]) + with tf.variable_scope(name): + We = tf.get_variable( + name='W', shape=[filter_size[0], filter_size[1], channels / n_group, n_filter], initializer=W_init, dtype=D_TYPE, trainable=True, **W_init_args) + if b_init: + bi = tf.get_variable(name='b', shape=n_filter, initializer=b_init, dtype=D_TYPE, trainable=True, **b_init_args) + if n_group == 1: + conv = groupConv(self.inputs, We) + else: + inputGroups = tf.split(axis=3, num_or_size_splits=n_group, value=self.inputs) + weightsGroups = tf.split(axis=3, num_or_size_splits=n_group, value=We) + convGroups = [groupConv(i, k) for i, k in zip(inputGroups, weightsGroups)] + conv = tf.concat(axis=3, values=convGroups) + if b_init: + conv = tf.add(conv, bi, name='add') + + self.outputs = act(conv) + self.all_layers = list(layer.all_layers) + self.all_params = list(layer.all_params) + self.all_drop = dict(layer.all_drop) + self.all_layers.append(self.outputs) + if b_init: + self.all_params.extend([We, bi]) + else: + self.all_params.append(We) + + # Alias AtrousConv1dLayer = atrous_conv1d Conv1d = conv1d