def separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None):
    "2-D convolution with separable filters.\n\n  Performs a depthwise convolution that acts separately on channels followed by\n  a pointwise convolution that mixes channels.  Note that this is separability\n  between dimensions `[1, 2]` and `3`, not spatial separability between\n  dimensions `1` and `2`.\n\n  In detail,\n\n      output[b, i, j, k] = sum_{di, dj, q, r]\n          input[b, strides[1] * i + di, strides[2] * j + dj, q] *\n          depthwise_filter[di, dj, q, r] *\n          pointwise_filter[0, 0, q * channel_multiplier + r, k]\n\n  `strides` controls the strides for the depthwise convolution only, since\n  the pointwise convolution has implicit strides of `[1, 1, 1, 1]`.  Must have\n  `strides[0] = strides[3] = 1`.  For the most common case of the same\n  horizontal and vertical strides, `strides = [1, stride, stride, 1]`.\n\n  Args:\n    input: 4-D `Tensor` with shape `[batch, in_height, in_width, in_channels]`.\n    depthwise_filter: 4-D `Tensor` with shape\n      `[filter_height, filter_width, in_channels, channel_multiplier]`.\n      Contains `in_channels` convolutional filters of depth 1.\n    pointwise_filter: 4-D `Tensor` with shape\n      `[1, 1, channel_multiplier * in_channels, out_channels]`.  Pointwise\n      filter to mix channels after `depthwise_filter` has convolved spatially.\n    strides: 1-D of size 4.  The strides for the depthwise convolution for\n      each 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 `[batch, out_height, out_width, out_channels]`.\n\n  Raises:\n    ValueError: If channel_multiplier * in_channels > out_channels,\n      which means that the separable convolution is overparameterized.\n  "
    with ops.op_scope([input, depthwise_filter, pointwise_filter], name, 'separable_conv2d') as name:
        input = ops.convert_to_tensor(input, name='tensor_in')
        depthwise_filter = ops.convert_to_tensor(depthwise_filter, name='depthwise_filter')
        pointwise_filter = ops.convert_to_tensor(pointwise_filter, name='pointwise_filter')
        if (pointwise_filter.get_shape().ndims is not None):
            assert (len(pointwise_filter.get_shape()) == 4)
            assert (pointwise_filter.get_shape()[0] == 1)
            assert (pointwise_filter.get_shape()[1] == 1)
            if (depthwise_filter.get_shape().ndims and input.get_shape().ndims):
                channel_multiplier = depthwise_filter.get_shape()[3]
                in_channels = input.get_shape()[3]
                out_channels = pointwise_filter.get_shape()[3]
                if ((channel_multiplier * in_channels) > out_channels):
                    raise ValueError(('Refusing to perform an overparameterized separable convolution: channel_multiplier * in_channels = %d * %d = %d > %d = out_channels' % (channel_multiplier, in_channels, (channel_multiplier * in_channels), out_channels)))
        depthwise = nn_ops.depthwise_conv2d_native(input, depthwise_filter, strides, padding, name='depthwise')
        return nn_ops.conv2d(depthwise, pointwise_filter, [1, 1, 1, 1], padding='VALID', name=name)
2-D convolution with separable filters.

Performs a depthwise convolution that acts separately on channels followed by
a pointwise convolution that mixes channels.  Note that this is separability
between dimensions `[1, 2]` and `3`, not spatial separability between
dimensions `1` and `2`.

In detail,

    output[b, i, j, k] = sum_{di, dj, q, r]
        input[b, strides[1] * i + di, strides[2] * j + dj, q] *
        depthwise_filter[di, dj, q, r] *
        pointwise_filter[0, 0, q * channel_multiplier + r, k]

`strides` controls the strides for the depthwise convolution only, since
the pointwise convolution has implicit strides of `[1, 1, 1, 1]`.  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 `Tensor` with shape `[batch, in_height, in_width, in_channels]`.
  depthwise_filter: 4-D `Tensor` with shape
    `[filter_height, filter_width, in_channels, channel_multiplier]`.
    Contains `in_channels` convolutional filters of depth 1.
  pointwise_filter: 4-D `Tensor` with shape
    `[1, 1, channel_multiplier * in_channels, out_channels]`.  Pointwise
    filter to mix channels after `depthwise_filter` has convolved spatially.
  strides: 1-D of size 4.  The strides for the depthwise convolution 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, out_channels]`.

Raises:
  ValueError: If channel_multiplier * in_channels > out_channels,
    which means that the separable convolution is overparameterized.
def separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, name=None):
    "2-D convolution with separable filters.\n\n  Performs a depthwise convolution that acts separately on channels followed by\n  a pointwise convolution that mixes channels.  Note that this is separability\n  between dimensions `[1, 2]` and `3`, not spatial separability between\n  dimensions `1` and `2`.\n\n  In detail,\n\n      output[b, i, j, k] = sum_{di, dj, q, r]\n          input[b, strides[1] * i + di, strides[2] * j + dj, q] *\n          depthwise_filter[di, dj, q, r] *\n          pointwise_filter[0, 0, q * channel_multiplier + r, k]\n\n  `strides` controls the strides for the depthwise convolution only, since\n  the pointwise convolution has implicit strides of `[1, 1, 1, 1]`.  Must have\n  `strides[0] = strides[3] = 1`.  For the most common case of the same\n  horizontal and vertical strides, `strides = [1, stride, stride, 1]`.\n\n  Args:\n    input: 4-D `Tensor` with shape `[batch, in_height, in_width, in_channels]`.\n    depthwise_filter: 4-D `Tensor` with shape\n      `[filter_height, filter_width, in_channels, channel_multiplier]`.\n      Contains `in_channels` convolutional filters of depth 1.\n    pointwise_filter: 4-D `Tensor` with shape\n      `[1, 1, channel_multiplier * in_channels, out_channels]`.  Pointwise\n      filter to mix channels after `depthwise_filter` has convolved spatially.\n    strides: 1-D of size 4.  The strides for the depthwise convolution for\n      each 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 `[batch, out_height, out_width, out_channels]`.\n\n  Raises:\n    ValueError: If channel_multiplier * in_channels > out_channels,\n      which means that the separable convolution is overparameterized.\n  "
    with ops.op_scope([input, depthwise_filter, pointwise_filter], name, 'separable_conv2d') as name:
        input = ops.convert_to_tensor(input, name='tensor_in')
        depthwise_filter = ops.convert_to_tensor(depthwise_filter, name='depthwise_filter')
        pointwise_filter = ops.convert_to_tensor(pointwise_filter, name='pointwise_filter')
        if (pointwise_filter.get_shape().ndims is not None):
            assert (len(pointwise_filter.get_shape()) == 4)
            assert (pointwise_filter.get_shape()[0] == 1)
            assert (pointwise_filter.get_shape()[1] == 1)
            if (depthwise_filter.get_shape().ndims and input.get_shape().ndims):
                channel_multiplier = depthwise_filter.get_shape()[3]
                in_channels = input.get_shape()[3]
                out_channels = pointwise_filter.get_shape()[3]
                if ((channel_multiplier * in_channels) > out_channels):
                    raise ValueError(('Refusing to perform an overparameterized separable convolution: channel_multiplier * in_channels = %d * %d = %d > %d = out_channels' % (channel_multiplier, in_channels, (channel_multiplier * in_channels), out_channels)))
        depthwise = nn_ops.depthwise_conv2d_native(input, depthwise_filter, strides, padding, name='depthwise')
        return nn_ops.conv2d(depthwise, pointwise_filter, [1, 1, 1, 1], padding='VALID', name=name)