def depthwise_conv2d(input, filter, strides, padding, name=None):
    "Depthwise 2-D convolution.\n\n  Given an input tensor of shape `[batch, in_height, in_width, in_channels]`\n  and a filter tensor of shape\n  `[filter_height, filter_width, in_channels, channel_multiplier]`\n  containing `in_channels` convolutional filters of depth 1, `depthwise_conv2d`\n  applies a different filter to each input channel (expanding from 1 channel\n  to `channel_multiplier` channels for each), then concatenates the results\n  together.  The output has `in_channels * channel_multiplier` channels.\n\n  In detail,\n\n      output[b, i, j, k * channel_multiplier + q] =\n          sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] *\n                       filter[di, dj, k, q]\n\n  Must have `strides[0] = strides[3] = 1`.  For the most common case of the\n  same horizontal and vertical strides, `strides = [1, stride, stride, 1]`.\n\n  Args:\n    input: 4-D with shape `[batch, in_height, in_width, in_channels]`.\n    filter: 4-D with shape\n      `[filter_height, filter_width, in_channels, channel_multiplier]`.\n    strides: 1-D of size 4.  The stride of the sliding window for each\n      dimension of `input`.\n    padding: A string, either `'VALID'` or `'SAME'`.  The padding algorithm.\n      See the [comment here](https://www.tensorflow.org/api_docs/python/nn.html#convolution)\n    name: A name for this operation (optional).\n\n  Returns:\n    A 4-D `Tensor` of shape\n    `[batch, out_height, out_width, in_channels * channel_multiplier].`\n  "
    with ops.op_scope([input, filter], name, 'depthwise') as name:
        input = ops.convert_to_tensor(input, name='tensor_in')
        filter = ops.convert_to_tensor(filter, name='filter_in')
        if (filter.get_shape().ndims is not None):
            assert (len(filter.get_shape()) == 4)
            in_channels = filter.get_shape()[2]
            if (input.get_shape().ndims is not None):
                assert (len(input.get_shape()) == 4)
                assert (input.get_shape()[3] == in_channels), ('Mismatched input depth %d and number of depthwise filters %d.' % (input.get_shape()[3].value, in_channels))
        else:
            assert (input.get_shape().ndims is not None), 'Either tensor must provide static shape information.'
            assert (input.get_shape().ndims == 4)
            in_channels = input.get_shape()[3]
        if (in_channels == 1):
            return nn_ops.conv2d(input, filter, strides, padding, name=name)
        else:
            return nn_ops.depthwise_conv2d_native(input, filter, strides, padding, name=name)
Depthwise 2-D convolution.

Given an input tensor of shape `[batch, in_height, in_width, in_channels]`
and a filter tensor of shape
`[filter_height, filter_width, in_channels, channel_multiplier]`
containing `in_channels` convolutional filters of depth 1, `depthwise_conv2d`
applies a different filter to each input channel (expanding from 1 channel
to `channel_multiplier` channels for each), then concatenates the results
together.  The output has `in_channels * channel_multiplier` channels.

In detail,

    output[b, i, j, k * channel_multiplier + q] =
        sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] *
                     filter[di, dj, k, q]

Must have `strides[0] = strides[3] = 1`.  For the most common case of the
same horizontal and vertical strides, `strides = [1, stride, stride, 1]`.

Args:
  input: 4-D with shape `[batch, in_height, in_width, in_channels]`.
  filter: 4-D with shape
    `[filter_height, filter_width, in_channels, channel_multiplier]`.
  strides: 1-D of size 4.  The stride of the sliding window for each
    dimension of `input`.
  padding: A string, either `'VALID'` or `'SAME'`.  The padding algorithm.
    See the [comment here](https://www.tensorflow.org/api_docs/python/nn.html#convolution)
  name: A name for this operation (optional).

Returns:
  A 4-D `Tensor` of shape
  `[batch, out_height, out_width, in_channels * channel_multiplier].`
def depthwise_conv2d(input, filter, strides, padding, name=None):
    "Depthwise 2-D convolution.\n\n  Given an input tensor of shape `[batch, in_height, in_width, in_channels]`\n  and a filter tensor of shape\n  `[filter_height, filter_width, in_channels, channel_multiplier]`\n  containing `in_channels` convolutional filters of depth 1, `depthwise_conv2d`\n  applies a different filter to each input channel (expanding from 1 channel\n  to `channel_multiplier` channels for each), then concatenates the results\n  together.  The output has `in_channels * channel_multiplier` channels.\n\n  In detail,\n\n      output[b, i, j, k * channel_multiplier + q] =\n          sum_{di, dj} input[b, strides[1] * i + di, strides[2] * j + dj, k] *\n                       filter[di, dj, k, q]\n\n  Must have `strides[0] = strides[3] = 1`.  For the most common case of the\n  same horizontal and vertical strides, `strides = [1, stride, stride, 1]`.\n\n  Args:\n    input: 4-D with shape `[batch, in_height, in_width, in_channels]`.\n    filter: 4-D with shape\n      `[filter_height, filter_width, in_channels, channel_multiplier]`.\n    strides: 1-D of size 4.  The stride of the sliding window for each\n      dimension of `input`.\n    padding: A string, either `'VALID'` or `'SAME'`.  The padding algorithm.\n      See the [comment here](https://www.tensorflow.org/api_docs/python/nn.html#convolution)\n    name: A name for this operation (optional).\n\n  Returns:\n    A 4-D `Tensor` of shape\n    `[batch, out_height, out_width, in_channels * channel_multiplier].`\n  "
    with ops.op_scope([input, filter], name, 'depthwise') as name:
        input = ops.convert_to_tensor(input, name='tensor_in')
        filter = ops.convert_to_tensor(filter, name='filter_in')
        if (filter.get_shape().ndims is not None):
            assert (len(filter.get_shape()) == 4)
            in_channels = filter.get_shape()[2]
            if (input.get_shape().ndims is not None):
                assert (len(input.get_shape()) == 4)
                assert (input.get_shape()[3] == in_channels), ('Mismatched input depth %d and number of depthwise filters %d.' % (input.get_shape()[3].value, in_channels))
        else:
            assert (input.get_shape().ndims is not None), 'Either tensor must provide static shape information.'
            assert (input.get_shape().ndims == 4)
            in_channels = input.get_shape()[3]
        if (in_channels == 1):
            return nn_ops.conv2d(input, filter, strides, padding, name=name)
        else:
            return nn_ops.depthwise_conv2d_native(input, filter, strides, padding, name=name)