Source code for tensorlayer.layers.convolution.depthwise_conv

#! /usr/bin/python
# -*- coding: utf-8 -*-

import tensorflow as tf

from tensorlayer.layers.core import Layer
from tensorlayer.layers.core import LayersConfig

from tensorlayer import logging

from tensorlayer.decorators import deprecated_alias

__all__ = [
    'DepthwiseConv2d',
]


[docs]class DepthwiseConv2d(Layer): """Separable/Depthwise Convolutional 2D layer, see `tf.nn.depthwise_conv2d <https://www.tensorflow.org/versions/master/api_docs/python/tf/nn/depthwise_conv2d>`__. Input: 4-D Tensor (batch, height, width, in_channels). Output: 4-D Tensor (batch, new height, new width, in_channels * depth_multiplier). Parameters ------------ prev_layer : :class:`Layer` Previous layer. filter_size : tuple of int The filter size (height, width). stride : tuple of int The stride step (height, width). act : activation function The activation function of this layer. padding : str The padding algorithm type: "SAME" or "VALID". dilation_rate: tuple of 2 int The dilation rate in which we sample input values across the height and width dimensions in atrous convolution. If it is greater than 1, then all values of strides must be 1. depth_multiplier : int The number of channels to expand to. W_init : initializer The initializer for the weight matrix. b_init : initializer or None The initializer for the bias vector. If None, skip bias. 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. Examples --------- >>> net = InputLayer(x, name='input') >>> net = Conv2d(net, 32, (3, 3), (2, 2), b_init=None, name='cin') >>> net = BatchNormLayer(net, act=tf.nn.relu, is_train=is_train, name='bnin') ... >>> net = DepthwiseConv2d(net, (3, 3), (1, 1), b_init=None, name='cdw1') >>> net = BatchNormLayer(net, act=tf.nn.relu, is_train=is_train, name='bn11') >>> net = Conv2d(net, 64, (1, 1), (1, 1), b_init=None, name='c1') >>> net = BatchNormLayer(net, act=tf.nn.relu, is_train=is_train, name='bn12') ... >>> net = DepthwiseConv2d(net, (3, 3), (2, 2), b_init=None, name='cdw2') >>> net = BatchNormLayer(net, act=tf.nn.relu, is_train=is_train, name='bn21') >>> net = Conv2d(net, 128, (1, 1), (1, 1), b_init=None, name='c2') >>> net = BatchNormLayer(net, act=tf.nn.relu, is_train=is_train, name='bn22') References ----------- - tflearn's `grouped_conv_2d <https://github.com/tflearn/tflearn/blob/3e0c3298ff508394f3ef191bcd7d732eb8860b2e/tflearn/layers/conv.py>`__ - keras's `separableconv2d <https://keras.io/layers/convolutional/#separableconv2d>`__ """ # https://zhuanlan.zhihu.com/p/31551004 https://github.com/xiaohu2015/DeepLearning_tutorials/blob/master/CNNs/MobileNet.py @deprecated_alias(layer='prev_layer', end_support_version=1.9) # TODO remove this line for the 1.9 release def __init__( self, prev_layer, shape=(3, 3), strides=(1, 1), act=None, padding='SAME', dilation_rate=(1, 1), depth_multiplier=1, 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='depthwise_conv2d', ): super(DepthwiseConv2d, self ).__init__(prev_layer=prev_layer, act=act, W_init_args=W_init_args, b_init_args=b_init_args, name=name) logging.info( "DepthwiseConv2d %s: shape: %s strides: %s pad: %s act: %s" % ( self.name, str(shape), str(strides), padding, self.act.__name__ if self.act is not None else 'No Activation' ) ) try: pre_channel = int(prev_layer.outputs.get_shape()[-1]) except Exception: # if pre_channel is ?, it happens when using Spatial Transformer Net pre_channel = 1 logging.info("[warnings] unknown input channels, set to 1") shape = [shape[0], shape[1], pre_channel, depth_multiplier] if len(strides) == 2: strides = [1, strides[0], strides[1], 1] if len(strides) != 4: raise AssertionError("len(strides) should be 4.") with tf.variable_scope(name): W = tf.get_variable( name='W_depthwise2d', shape=shape, initializer=W_init, dtype=LayersConfig.tf_dtype, **self.W_init_args ) # [filter_height, filter_width, in_channels, depth_multiplier] self.outputs = tf.nn.depthwise_conv2d(self.inputs, W, strides=strides, padding=padding, rate=dilation_rate) if b_init: b = tf.get_variable( name='b_depthwise2d', shape=(pre_channel * depth_multiplier), initializer=b_init, dtype=LayersConfig.tf_dtype, **self.b_init_args ) self.outputs = tf.nn.bias_add(self.outputs, b, name='bias_add') self.outputs = self._apply_activation(self.outputs) self._add_layers(self.outputs) if b_init: self._add_params([W, b]) else: self._add_params(W)