1# Copyright 2018 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Tests for separable convolutional layers."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import print_function
20
21from absl.testing import parameterized
22import numpy as np
23
24from tensorflow.python import keras
25from tensorflow.python.keras import keras_parameterized
26from tensorflow.python.keras import testing_utils
27from tensorflow.python.platform import test
28
29
30@keras_parameterized.run_all_keras_modes
31class SeparableConv1DTest(keras_parameterized.TestCase):
32
33  def _run_test(self, kwargs):
34    num_samples = 2
35    stack_size = 3
36    length = 7
37
38    with self.cached_session(use_gpu=True):
39      testing_utils.layer_test(
40          keras.layers.SeparableConv1D,
41          kwargs=kwargs,
42          input_shape=(num_samples, length, stack_size))
43
44  @parameterized.named_parameters(
45      ('padding_valid', {'padding': 'valid'}),
46      ('padding_same', {'padding': 'same'}),
47      ('padding_same_dilation_2', {'padding': 'same', 'dilation_rate': 2}),
48      ('padding_causal', {'padding': 'causal'}),
49      ('strides', {'strides': 2}),
50      ('dilation_rate', {'dilation_rate': 2}),
51      ('depth_multiplier', {'depth_multiplier': 2}),
52  )
53  def test_separable_conv1d(self, kwargs):
54    kwargs['filters'] = 2
55    kwargs['kernel_size'] = 3
56    self._run_test(kwargs)
57
58  def test_separable_conv1d_regularizers(self):
59    kwargs = {
60        'filters': 3,
61        'kernel_size': 3,
62        'padding': 'valid',
63        'depthwise_regularizer': 'l2',
64        'pointwise_regularizer': 'l2',
65        'bias_regularizer': 'l2',
66        'activity_regularizer': 'l2',
67        'strides': 1
68    }
69    with self.cached_session(use_gpu=True):
70      layer = keras.layers.SeparableConv1D(**kwargs)
71      layer.build((None, 5, 2))
72      self.assertEqual(len(layer.losses), 3)
73      layer(keras.backend.variable(np.ones((1, 5, 2))))
74      self.assertEqual(len(layer.losses), 4)
75
76  def test_separable_conv1d_constraints(self):
77    d_constraint = lambda x: x
78    p_constraint = lambda x: x
79    b_constraint = lambda x: x
80
81    kwargs = {
82        'filters': 3,
83        'kernel_size': 3,
84        'padding': 'valid',
85        'pointwise_constraint': p_constraint,
86        'depthwise_constraint': d_constraint,
87        'bias_constraint': b_constraint,
88        'strides': 1
89    }
90    with self.cached_session(use_gpu=True):
91      layer = keras.layers.SeparableConv1D(**kwargs)
92      layer.build((None, 5, 2))
93      self.assertEqual(layer.depthwise_kernel.constraint, d_constraint)
94      self.assertEqual(layer.pointwise_kernel.constraint, p_constraint)
95      self.assertEqual(layer.bias.constraint, b_constraint)
96
97
98@keras_parameterized.run_all_keras_modes
99class SeparableConv2DTest(keras_parameterized.TestCase):
100
101  def _run_test(self, kwargs):
102    num_samples = 2
103    stack_size = 3
104    num_row = 7
105    num_col = 6
106
107    with self.cached_session(use_gpu=True):
108      testing_utils.layer_test(
109          keras.layers.SeparableConv2D,
110          kwargs=kwargs,
111          input_shape=(num_samples, num_row, num_col, stack_size))
112
113  @parameterized.named_parameters(
114      ('padding_valid', {'padding': 'valid'}),
115      ('padding_same', {'padding': 'same'}),
116      ('padding_same_dilation_2', {'padding': 'same', 'dilation_rate': 2}),
117      ('strides', {'strides': 2}),
118      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
119      # TODO(b/62340061): Support channels_first on CPU.
120      ('data_format', {'data_format': 'channels_first'}),
121      ('dilation_rate', {'dilation_rate': 2}),
122      ('depth_multiplier', {'depth_multiplier': 2}),
123  )
124  def test_separable_conv2d(self, kwargs):
125    kwargs['filters'] = 2
126    kwargs['kernel_size'] = 3
127    if 'data_format' not in kwargs or test.is_gpu_available(cuda_only=True):
128      self._run_test(kwargs)
129
130  def test_separable_conv2d_regularizers(self):
131    kwargs = {
132        'filters': 3,
133        'kernel_size': 3,
134        'padding': 'valid',
135        'depthwise_regularizer': 'l2',
136        'pointwise_regularizer': 'l2',
137        'bias_regularizer': 'l2',
138        'activity_regularizer': 'l2',
139        'strides': 1
140    }
141    with self.cached_session(use_gpu=True):
142      layer = keras.layers.SeparableConv2D(**kwargs)
143      layer.build((None, 5, 5, 2))
144      self.assertEqual(len(layer.losses), 3)
145      layer(keras.backend.variable(np.ones((1, 5, 5, 2))))
146      self.assertEqual(len(layer.losses), 4)
147
148  def test_separable_conv2d_constraints(self):
149    d_constraint = lambda x: x
150    p_constraint = lambda x: x
151    b_constraint = lambda x: x
152
153    kwargs = {
154        'filters': 3,
155        'kernel_size': 3,
156        'padding': 'valid',
157        'pointwise_constraint': p_constraint,
158        'depthwise_constraint': d_constraint,
159        'bias_constraint': b_constraint,
160        'strides': 1
161    }
162    with self.cached_session(use_gpu=True):
163      layer = keras.layers.SeparableConv2D(**kwargs)
164      layer.build((None, 5, 5, 2))
165      self.assertEqual(layer.depthwise_kernel.constraint, d_constraint)
166      self.assertEqual(layer.pointwise_kernel.constraint, p_constraint)
167      self.assertEqual(layer.bias.constraint, b_constraint)
168