• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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 convolutional layers."""
16
17from absl.testing import parameterized
18import numpy as np
19
20from tensorflow.python import keras
21from tensorflow.python.eager import context
22from tensorflow.python.eager import def_function
23from tensorflow.python.framework import tensor_spec
24from tensorflow.python.framework import test_util
25from tensorflow.python.keras import keras_parameterized
26from tensorflow.python.keras import testing_utils
27from tensorflow.python.ops import array_ops
28from tensorflow.python.ops import nn
29from tensorflow.python.ops import random_ops
30from tensorflow.python.platform import test
31
32
33@keras_parameterized.run_all_keras_modes
34class Conv1DTest(keras_parameterized.TestCase):
35
36  def _run_test(self, kwargs, expected_output_shape):
37    num_samples = 2
38    stack_size = 3
39    length = 7
40
41    with self.cached_session():
42      testing_utils.layer_test(
43          keras.layers.Conv1D,
44          kwargs=kwargs,
45          input_shape=(num_samples, length, stack_size),
46          expected_output_shape=expected_output_shape)
47
48  def _run_test_extra_batch_dim(self, kwargs, expected_output_shape):
49    batch_shape = (2, 11)
50    stack_size = 3
51    length = 7
52
53    with self.cached_session():
54      if expected_output_shape is not None:
55        expected_output_shape = (None,) + expected_output_shape
56
57      testing_utils.layer_test(
58          keras.layers.Conv1D,
59          kwargs=kwargs,
60          input_shape=batch_shape + (length, stack_size),
61          expected_output_shape=expected_output_shape)
62
63  @parameterized.named_parameters(
64      ('padding_valid', {
65          'padding': 'valid'
66      }, (None, 5, 2)),
67      ('padding_same', {
68          'padding': 'same'
69      }, (None, 7, 2)),
70      ('padding_same_dilation_2', {
71          'padding': 'same',
72          'dilation_rate': 2
73      }, (None, 7, 2)),
74      ('padding_same_dilation_3', {
75          'padding': 'same',
76          'dilation_rate': 3
77      }, (None, 7, 2)),
78      ('padding_causal', {
79          'padding': 'causal'
80      }, (None, 7, 2)),
81      ('strides', {
82          'strides': 2
83      }, (None, 3, 2)),
84      ('dilation_rate', {
85          'dilation_rate': 2
86      }, (None, 3, 2)),
87      # Only runs on GPU with CUDA, groups are not supported on CPU.
88      # https://github.com/tensorflow/tensorflow/issues/29005
89      ('group', {
90          'groups': 3,
91          'filters': 6
92      }, (None, 5, 6), True),
93  )
94  def test_conv1d(self, kwargs, expected_output_shape, requires_gpu=False):
95    kwargs['filters'] = kwargs.get('filters', 2)
96    kwargs['kernel_size'] = 3
97    if not requires_gpu or test.is_gpu_available(cuda_only=True):
98      self._run_test(kwargs, expected_output_shape)
99      self._run_test_extra_batch_dim(kwargs, expected_output_shape)
100
101  def test_conv1d_regularizers(self):
102    kwargs = {
103        'filters': 3,
104        'kernel_size': 3,
105        'padding': 'valid',
106        'kernel_regularizer': 'l2',
107        'bias_regularizer': 'l2',
108        'activity_regularizer': 'l2',
109        'strides': 1
110    }
111    with self.cached_session():
112      layer = keras.layers.Conv1D(**kwargs)
113      layer.build((None, 5, 2))
114      self.assertEqual(len(layer.losses), 2)
115      layer(keras.backend.variable(np.ones((1, 5, 2))))
116      self.assertEqual(len(layer.losses), 3)
117
118  def test_conv1d_constraints(self):
119    k_constraint = lambda x: x
120    b_constraint = lambda x: x
121
122    kwargs = {
123        'filters': 3,
124        'kernel_size': 3,
125        'padding': 'valid',
126        'kernel_constraint': k_constraint,
127        'bias_constraint': b_constraint,
128        'strides': 1
129    }
130    with self.cached_session():
131      layer = keras.layers.Conv1D(**kwargs)
132      layer.build((None, 5, 2))
133      self.assertEqual(layer.kernel.constraint, k_constraint)
134      self.assertEqual(layer.bias.constraint, b_constraint)
135
136  def test_conv1d_recreate_conv(self):
137    with self.cached_session():
138      layer = keras.layers.Conv1D(filters=1,
139                                  kernel_size=3,
140                                  strides=1,
141                                  dilation_rate=2,
142                                  padding='causal')
143      inpt1 = np.random.normal(size=[1, 2, 1])
144      inpt2 = np.random.normal(size=[1, 1, 1])
145      outp1_shape = layer(inpt1).shape
146      _ = layer(inpt2).shape
147      self.assertEqual(outp1_shape, layer(inpt1).shape)
148
149  def test_conv1d_recreate_conv_unknown_dims(self):
150    with self.cached_session():
151      layer = keras.layers.Conv1D(filters=1,
152                                  kernel_size=3,
153                                  strides=1,
154                                  dilation_rate=2,
155                                  padding='causal')
156
157      inpt1 = np.random.normal(size=[1, 9, 1]).astype(np.float32)
158      inpt2 = np.random.normal(size=[1, 2, 1]).astype(np.float32)
159      outp1_shape = layer(inpt1).shape
160
161      @def_function.function(input_signature=[
162          tensor_spec.TensorSpec([1, None, 1])])
163      def fn(inpt):
164        return layer(inpt)
165
166      fn(inpt2)
167      self.assertEqual(outp1_shape, layer(inpt1).shape)
168
169
170@keras_parameterized.run_all_keras_modes
171class Conv2DTest(keras_parameterized.TestCase):
172
173  def _run_test(self, kwargs, expected_output_shape, spatial_shape=(7, 6)):
174    num_samples = 2
175    stack_size = 3
176    num_row, num_col = spatial_shape
177    input_data = None
178    # Generate valid input data.
179    if None in spatial_shape:
180      input_data_shape = (num_samples, num_row or 7, num_col or 6, stack_size)
181      input_data = 10 * np.random.random(input_data_shape).astype(np.float32)
182
183    with self.cached_session():
184      testing_utils.layer_test(
185          keras.layers.Conv2D,
186          kwargs=kwargs,
187          input_shape=(num_samples, num_row, num_col, stack_size),
188          input_data=input_data,
189          expected_output_shape=expected_output_shape)
190
191  def _run_test_extra_batch_dim(self,
192                                kwargs,
193                                expected_output_shape,
194                                spatial_shape=(7, 6)):
195    batch_shape = (2, 11)
196    stack_size = 3
197    num_row, num_col = spatial_shape
198    input_data = None
199    # Generate valid input data.
200    if None in spatial_shape:
201      input_data_shape = batch_shape + (num_row or 7, num_col or 6, stack_size)
202      input_data = 10 * np.random.random(input_data_shape).astype(np.float32)
203
204    with self.cached_session():
205      if expected_output_shape is not None:
206        expected_output_shape = (None,) + expected_output_shape
207      testing_utils.layer_test(
208          keras.layers.Conv2D,
209          kwargs=kwargs,
210          input_shape=batch_shape + (num_row, num_col, stack_size),
211          input_data=input_data,
212          expected_output_shape=expected_output_shape)
213
214  @parameterized.named_parameters(
215      ('padding_valid', {
216          'padding': 'valid'
217      }, (None, 5, 4, 2)),
218      ('padding_same', {
219          'padding': 'same'
220      }, (None, 7, 6, 2)),
221      ('padding_same_dilation_2', {
222          'padding': 'same',
223          'dilation_rate': 2
224      }, (None, 7, 6, 2)),
225      ('strides', {
226          'strides': (2, 2)
227      }, (None, 3, 2, 2)),
228      ('dilation_rate', {
229          'dilation_rate': (2, 2)
230      }, (None, 3, 2, 2)),
231      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
232      # TODO(b/62340061): Support channels_first on CPU.
233      ('data_format', {
234          'data_format': 'channels_first'
235      }, None, True),
236      # Only runs on GPU with CUDA, groups are not supported on CPU.
237      # https://github.com/tensorflow/tensorflow/issues/29005
238      ('group', {
239          'groups': 3,
240          'filters': 6
241      }, (None, 5, 4, 6), True),
242      ('dilation_2_unknown_width', {
243          'dilation_rate': (2, 2)
244      }, (None, None, 2, 2), False, (None, 6)),
245      ('dilation_2_unknown_height', {
246          'dilation_rate': (2, 2)
247      }, (None, 3, None, 2), False, (7, None)),
248  )
249  def test_conv2d(self,
250                  kwargs,
251                  expected_output_shape=None,
252                  requires_gpu=False,
253                  spatial_shape=(7, 6)):
254    kwargs['filters'] = kwargs.get('filters', 2)
255    kwargs['kernel_size'] = (3, 3)
256    if not requires_gpu or test.is_gpu_available(cuda_only=True):
257      self._run_test(kwargs, expected_output_shape, spatial_shape)
258      self._run_test_extra_batch_dim(kwargs, expected_output_shape,
259                                     spatial_shape)
260
261  def test_conv2d_regularizers(self):
262    kwargs = {
263        'filters': 3,
264        'kernel_size': 3,
265        'padding': 'valid',
266        'kernel_regularizer': 'l2',
267        'bias_regularizer': 'l2',
268        'activity_regularizer': 'l2',
269        'strides': 1
270    }
271    with self.cached_session():
272      layer = keras.layers.Conv2D(**kwargs)
273      layer.build((None, 5, 5, 2))
274      self.assertEqual(len(layer.losses), 2)
275      layer(keras.backend.variable(np.ones((1, 5, 5, 2))))
276      self.assertEqual(len(layer.losses), 3)
277
278  def test_conv2d_constraints(self):
279    k_constraint = lambda x: x
280    b_constraint = lambda x: x
281
282    kwargs = {
283        'filters': 3,
284        'kernel_size': 3,
285        'padding': 'valid',
286        'kernel_constraint': k_constraint,
287        'bias_constraint': b_constraint,
288        'strides': 1
289    }
290    with self.cached_session():
291      layer = keras.layers.Conv2D(**kwargs)
292      layer.build((None, 5, 5, 2))
293      self.assertEqual(layer.kernel.constraint, k_constraint)
294      self.assertEqual(layer.bias.constraint, b_constraint)
295
296  def test_conv2d_zero_kernel_size(self):
297    kwargs = {'filters': 2, 'kernel_size': 0}
298    with self.assertRaises(ValueError):
299      keras.layers.Conv2D(**kwargs)
300
301
302@keras_parameterized.run_all_keras_modes
303class Conv3DTest(keras_parameterized.TestCase):
304
305  def _run_test(self, kwargs, expected_output_shape, validate_training=True):
306    num_samples = 2
307    stack_size = 3
308    num_row = 7
309    num_col = 6
310    depth = 5
311
312    with self.cached_session():
313      testing_utils.layer_test(
314          keras.layers.Conv3D,
315          kwargs=kwargs,
316          input_shape=(num_samples, depth, num_row, num_col, stack_size),
317          expected_output_shape=expected_output_shape,
318          validate_training=validate_training)
319
320  def _run_test_extra_batch_dim(self,
321                                kwargs,
322                                expected_output_shape,
323                                validate_training=True):
324    batch_shape = (2, 11)
325    stack_size = 3
326    num_row = 7
327    num_col = 6
328    depth = 5
329
330    with self.cached_session():
331      if expected_output_shape is not None:
332        expected_output_shape = (None,) + expected_output_shape
333
334      testing_utils.layer_test(
335          keras.layers.Conv3D,
336          kwargs=kwargs,
337          input_shape=batch_shape + (depth, num_row, num_col, stack_size),
338          expected_output_shape=expected_output_shape,
339          validate_training=validate_training)
340
341  @parameterized.named_parameters(
342      ('padding_valid', {
343          'padding': 'valid'
344      }, (None, 3, 5, 4, 2)),
345      ('padding_same', {
346          'padding': 'same'
347      }, (None, 5, 7, 6, 2)),
348      ('strides', {
349          'strides': (2, 2, 2)
350      }, (None, 2, 3, 2, 2)),
351      ('dilation_rate', {
352          'dilation_rate': (2, 2, 2)
353      }, (None, 1, 3, 2, 2)),
354      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
355      # TODO(b/62340061): Support channels_first on CPU.
356      ('data_format', {
357          'data_format': 'channels_first'
358      }, None, True),
359      # Only runs on GPU with CUDA, groups are not supported on CPU.
360      # https://github.com/tensorflow/tensorflow/issues/29005
361      ('group', {
362          'groups': 3,
363          'filters': 6
364      }, (None, 3, 5, 4, 6), True),
365  )
366  def test_conv3d(self, kwargs, expected_output_shape=None, requires_gpu=False):
367    kwargs['filters'] = kwargs.get('filters', 2)
368    kwargs['kernel_size'] = (3, 3, 3)
369    # train_on_batch currently fails with XLA enabled on GPUs
370    test_training = 'groups' not in kwargs or not test_util.is_xla_enabled()
371    if not requires_gpu or test.is_gpu_available(cuda_only=True):
372      self._run_test(kwargs, expected_output_shape, test_training)
373      self._run_test_extra_batch_dim(kwargs, expected_output_shape,
374                                     test_training)
375
376  def test_conv3d_regularizers(self):
377    kwargs = {
378        'filters': 3,
379        'kernel_size': 3,
380        'padding': 'valid',
381        'kernel_regularizer': 'l2',
382        'bias_regularizer': 'l2',
383        'activity_regularizer': 'l2',
384        'strides': 1
385    }
386    with self.cached_session():
387      layer = keras.layers.Conv3D(**kwargs)
388      layer.build((None, 5, 5, 5, 2))
389      self.assertEqual(len(layer.losses), 2)
390      self.assertEqual(len(layer.losses), 2)
391      layer(keras.backend.variable(np.ones((1, 5, 5, 5, 2))))
392      self.assertEqual(len(layer.losses), 3)
393
394  def test_conv3d_constraints(self):
395    k_constraint = lambda x: x
396    b_constraint = lambda x: x
397
398    kwargs = {
399        'filters': 3,
400        'kernel_size': 3,
401        'padding': 'valid',
402        'kernel_constraint': k_constraint,
403        'bias_constraint': b_constraint,
404        'strides': 1
405    }
406    with self.cached_session():
407      layer = keras.layers.Conv3D(**kwargs)
408      layer.build((None, 5, 5, 5, 2))
409      self.assertEqual(layer.kernel.constraint, k_constraint)
410      self.assertEqual(layer.bias.constraint, b_constraint)
411
412  def test_conv3d_dynamic_shape(self):
413    input_data = np.random.random((1, 3, 3, 3, 3)).astype(np.float32)
414    with self.cached_session():
415      # Won't raise error here.
416      testing_utils.layer_test(
417          keras.layers.Conv3D,
418          kwargs={
419              'data_format': 'channels_last',
420              'filters': 3,
421              'kernel_size': 3
422          },
423          input_shape=(None, None, None, None, 3),
424          input_data=input_data)
425      if test.is_gpu_available(cuda_only=True):
426        testing_utils.layer_test(
427            keras.layers.Conv3D,
428            kwargs={
429                'data_format': 'channels_first',
430                'filters': 3,
431                'kernel_size': 3
432            },
433            input_shape=(None, 3, None, None, None),
434            input_data=input_data)
435
436
437@keras_parameterized.run_all_keras_modes(always_skip_v1=True)
438class GroupedConvTest(keras_parameterized.TestCase):
439
440  @parameterized.named_parameters(
441      ('Conv1D', keras.layers.Conv1D),
442      ('Conv2D', keras.layers.Conv2D),
443      ('Conv3D', keras.layers.Conv3D),
444  )
445  def test_group_conv_incorrect_use(self, layer):
446    with self.assertRaisesRegex(ValueError, 'The number of filters'):
447      layer(16, 3, groups=3)
448    with self.assertRaisesRegex(ValueError, 'The number of input channels'):
449      layer(16, 3, groups=4).build((32, 12, 12, 3))
450
451  @parameterized.named_parameters(
452      ('Conv1D', keras.layers.Conv1D, (32, 12, 32)),
453      ('Conv2D', keras.layers.Conv2D, (32, 12, 12, 32)),
454      ('Conv3D', keras.layers.Conv3D, (32, 12, 12, 12, 32)),
455  )
456  def test_group_conv(self, layer_cls, input_shape):
457    if test.is_gpu_available(cuda_only=True):
458      with testing_utils.use_gpu():
459        inputs = random_ops.random_uniform(shape=input_shape)
460
461        layer = layer_cls(16, 3, groups=4, use_bias=False)
462        layer.build(input_shape)
463
464        input_slices = array_ops.split(inputs, 4, axis=-1)
465        weight_slices = array_ops.split(layer.kernel, 4, axis=-1)
466        expected_outputs = array_ops.concat([
467            nn.convolution_v2(inputs, weights)
468            for inputs, weights in zip(input_slices, weight_slices)
469        ],
470                                            axis=-1)
471        self.assertAllClose(
472            layer(inputs), expected_outputs, rtol=3e-5, atol=3e-5)
473
474  def test_group_conv_depthwise(self):
475    if test.is_gpu_available(cuda_only=True):
476      with testing_utils.use_gpu():
477        inputs = random_ops.random_uniform(shape=(3, 27, 27, 32))
478
479        layer = keras.layers.Conv2D(32, 3, groups=32, use_bias=False)
480        layer.build((3, 27, 27, 32))
481
482        weights_dw = array_ops.reshape(layer.kernel, [3, 3, 32, 1])
483        expected_outputs = nn.depthwise_conv2d(
484            inputs, weights_dw, strides=[1, 1, 1, 1], padding='VALID')
485
486        self.assertAllClose(layer(inputs), expected_outputs, rtol=1e-5)
487
488
489@keras_parameterized.run_all_keras_modes
490class Conv1DTransposeTest(keras_parameterized.TestCase):
491
492  def _run_test(self, kwargs, expected_output_shape):
493    num_samples = 2
494    stack_size = 3
495    num_col = 6
496
497    with testing_utils.use_gpu():
498      testing_utils.layer_test(
499          keras.layers.Conv1DTranspose,
500          kwargs=kwargs,
501          input_shape=(num_samples, num_col, stack_size),
502          expected_output_shape=expected_output_shape)
503
504  @parameterized.named_parameters(
505      ('padding_valid', {'padding': 'valid'}, (None, 8, 2)),
506      ('padding_same', {'padding': 'same'}, (None, 6, 2)),
507      ('strides', {'strides': 2}, (None, 13, 2)),
508      # Only runs on GPU with CUDA, dilation_rate>1 is not supported on CPU.
509      ('dilation_rate', {'dilation_rate': 2}, (None, 10, 2)),
510      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
511      # TODO(b/62340061): Support channels_first on CPU.
512      ('data_format', {'data_format': 'channels_first'}),
513  )
514  def test_conv1d_transpose(self, kwargs, expected_output_shape=None):
515    kwargs['filters'] = 2
516    kwargs['kernel_size'] = 3
517    if (('data_format' not in kwargs and 'dilation_rate' not in kwargs) or
518        test.is_gpu_available(cuda_only=True)):
519      self._run_test(kwargs, expected_output_shape)
520
521
522@keras_parameterized.run_all_keras_modes
523class Conv3DTransposeTest(keras_parameterized.TestCase):
524
525  def _run_test(self, kwargs, expected_output_shape):
526    num_samples = 2
527    stack_size = 3
528    num_row = 7
529    num_col = 6
530    depth = 5
531
532    with testing_utils.use_gpu():
533      testing_utils.layer_test(
534          keras.layers.Conv3DTranspose,
535          kwargs=kwargs,
536          input_shape=(num_samples, depth, num_row, num_col, stack_size),
537          expected_output_shape=expected_output_shape)
538
539  @parameterized.named_parameters(
540      ('padding_valid', {'padding': 'valid'}, (None, 7, 9, 8, 2)),
541      ('padding_same', {'padding': 'same'}, (None, 5, 7, 6, 2)),
542      ('strides', {'strides': (2, 2, 2)}, (None, 11, 15, 13, 2)),
543      ('dilation_rate', {'dilation_rate': (2, 2, 2)}, (None, 7, 9, 8, 2)),
544      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
545      # TODO(b/62340061): Support channels_first on CPU.
546      ('data_format', {'data_format': 'channels_first'}),
547  )
548  def test_conv3d_transpose(self, kwargs, expected_output_shape=None):
549    kwargs['filters'] = 2
550    kwargs['kernel_size'] = (3, 3, 3)
551    if 'data_format' not in kwargs or test.is_gpu_available(cuda_only=True):
552      self._run_test(kwargs, expected_output_shape)
553
554
555@keras_parameterized.run_all_keras_modes
556class ConvSequentialTest(keras_parameterized.TestCase):
557
558  def _run_test(self, conv_layer_cls, kwargs, input_shape1, input_shape2,
559                expected_output_shape1, expected_output_shape2):
560    kwargs['filters'] = 1
561    kwargs['kernel_size'] = 3
562    kwargs['dilation_rate'] = 2
563    with self.cached_session():
564      layer = conv_layer_cls(**kwargs)
565      output1 = layer(np.zeros(input_shape1))
566      self.assertEqual(output1.shape, expected_output_shape1)
567      output2 = layer(np.zeros(input_shape2))
568      self.assertEqual(output2.shape, expected_output_shape2)
569
570  @parameterized.named_parameters(
571      ('padding_valid', {'padding': 'valid'},
572       (1, 8, 2), (1, 5, 2), (1, 4, 1), (1, 1, 1)),
573      ('padding_same', {'padding': 'same'},
574       (1, 8, 2), (1, 5, 2), (1, 8, 1), (1, 5, 1)),
575      ('padding_causal', {'padding': 'causal'},
576       (1, 8, 2), (1, 5, 2), (1, 8, 1), (1, 5, 1)),
577  )
578  def test_conv1d(self, kwargs, input_shape1, input_shape2,
579                  expected_output_shape1, expected_output_shape2):
580    self._run_test(keras.layers.Conv1D, kwargs, input_shape1, input_shape2,
581                   expected_output_shape1, expected_output_shape2)
582
583  @parameterized.named_parameters(
584      ('padding_valid', {'padding': 'valid'},
585       (1, 7, 6, 2), (1, 6, 5, 2), (1, 3, 2, 1), (1, 2, 1, 1)),
586      ('padding_same', {'padding': 'same'},
587       (1, 7, 6, 2), (1, 6, 5, 2), (1, 7, 6, 1), (1, 6, 5, 1)),
588  )
589  def test_conv2d(self, kwargs, input_shape1, input_shape2,
590                  expected_output_shape1, expected_output_shape2):
591    self._run_test(keras.layers.Conv2D, kwargs, input_shape1, input_shape2,
592                   expected_output_shape1, expected_output_shape2)
593
594  @parameterized.named_parameters(
595      ('padding_valid', {'padding': 'valid'},
596       (1, 5, 7, 6, 2), (1, 8, 6, 5, 2), (1, 1, 3, 2, 1), (1, 4, 2, 1, 1)),
597      ('padding_same', {'padding': 'same'},
598       (1, 5, 7, 6, 2), (1, 8, 6, 5, 2), (1, 5, 7, 6, 1), (1, 8, 6, 5, 1)),
599  )
600  def test_conv3d(self, kwargs, input_shape1, input_shape2,
601                  expected_output_shape1, expected_output_shape2):
602    self._run_test(keras.layers.Conv3D, kwargs, input_shape1, input_shape2,
603                   expected_output_shape1, expected_output_shape2)
604
605  def test_dynamic_shape(self):
606    with self.cached_session():
607      layer = keras.layers.Conv3D(2, 3)
608      input_shape = (5, None, None, 2)
609      inputs = keras.Input(shape=input_shape)
610      x = layer(inputs)
611      # Won't raise error here with None values in input shape (b/144282043).
612      layer(x)
613
614
615@keras_parameterized.run_all_keras_modes
616class ZeroPaddingTest(keras_parameterized.TestCase):
617
618  def test_zero_padding_1d(self):
619    num_samples = 2
620    input_dim = 2
621    num_steps = 5
622    shape = (num_samples, num_steps, input_dim)
623    inputs = np.ones(shape)
624
625    with self.cached_session():
626      # basic test
627      testing_utils.layer_test(
628          keras.layers.ZeroPadding1D,
629          kwargs={'padding': 2},
630          input_shape=inputs.shape)
631      testing_utils.layer_test(
632          keras.layers.ZeroPadding1D,
633          kwargs={'padding': (1, 2)},
634          input_shape=inputs.shape)
635
636      # correctness test
637      layer = keras.layers.ZeroPadding1D(padding=2)
638      layer.build(shape)
639      output = layer(keras.backend.variable(inputs))
640      if context.executing_eagerly():
641        np_output = output.numpy()
642      else:
643        np_output = keras.backend.eval(output)
644      for offset in [0, 1, -1, -2]:
645        np.testing.assert_allclose(np_output[:, offset, :], 0.)
646      np.testing.assert_allclose(np_output[:, 2:-2, :], 1.)
647
648      layer = keras.layers.ZeroPadding1D(padding=(1, 2))
649      layer.build(shape)
650      output = layer(keras.backend.variable(inputs))
651      if context.executing_eagerly():
652        np_output = output.numpy()
653      else:
654        np_output = keras.backend.eval(output)
655      for left_offset in [0]:
656        np.testing.assert_allclose(np_output[:, left_offset, :], 0.)
657      for right_offset in [-1, -2]:
658        np.testing.assert_allclose(np_output[:, right_offset, :], 0.)
659      np.testing.assert_allclose(np_output[:, 1:-2, :], 1.)
660      layer.get_config()
661
662    # test incorrect use
663    with self.assertRaises(ValueError):
664      keras.layers.ZeroPadding1D(padding=(1, 1, 1))
665    with self.assertRaises(ValueError):
666      keras.layers.ZeroPadding1D(padding=None)
667
668  @parameterized.named_parameters(('channels_first', 'channels_first'),
669                                  ('channels_last', 'channels_last'))
670  def test_zero_padding_2d(self, data_format):
671    num_samples = 2
672    stack_size = 2
673    input_num_row = 4
674    input_num_col = 5
675    if data_format == 'channels_first':
676      inputs = np.ones((num_samples, stack_size, input_num_row, input_num_col))
677    elif data_format == 'channels_last':
678      inputs = np.ones((num_samples, input_num_row, input_num_col, stack_size))
679
680    # basic test
681    with self.cached_session():
682      testing_utils.layer_test(
683          keras.layers.ZeroPadding2D,
684          kwargs={
685              'padding': (2, 2),
686              'data_format': data_format
687          },
688          input_shape=inputs.shape)
689      testing_utils.layer_test(
690          keras.layers.ZeroPadding2D,
691          kwargs={
692              'padding': ((1, 2), (3, 4)),
693              'data_format': data_format
694          },
695          input_shape=inputs.shape)
696
697    # correctness test
698    with self.cached_session():
699      layer = keras.layers.ZeroPadding2D(
700          padding=(2, 2), data_format=data_format)
701      layer.build(inputs.shape)
702      output = layer(keras.backend.variable(inputs))
703      if context.executing_eagerly():
704        np_output = output.numpy()
705      else:
706        np_output = keras.backend.eval(output)
707      if data_format == 'channels_last':
708        for offset in [0, 1, -1, -2]:
709          np.testing.assert_allclose(np_output[:, offset, :, :], 0.)
710          np.testing.assert_allclose(np_output[:, :, offset, :], 0.)
711        np.testing.assert_allclose(np_output[:, 2:-2, 2:-2, :], 1.)
712      elif data_format == 'channels_first':
713        for offset in [0, 1, -1, -2]:
714          np.testing.assert_allclose(np_output[:, :, offset, :], 0.)
715          np.testing.assert_allclose(np_output[:, :, :, offset], 0.)
716        np.testing.assert_allclose(np_output[:, 2:-2, 2:-2, :], 1.)
717
718      layer = keras.layers.ZeroPadding2D(
719          padding=((1, 2), (3, 4)), data_format=data_format)
720      layer.build(inputs.shape)
721      output = layer(keras.backend.variable(inputs))
722      if context.executing_eagerly():
723        np_output = output.numpy()
724      else:
725        np_output = keras.backend.eval(output)
726      if data_format == 'channels_last':
727        for top_offset in [0]:
728          np.testing.assert_allclose(np_output[:, top_offset, :, :], 0.)
729        for bottom_offset in [-1, -2]:
730          np.testing.assert_allclose(np_output[:, bottom_offset, :, :], 0.)
731        for left_offset in [0, 1, 2]:
732          np.testing.assert_allclose(np_output[:, :, left_offset, :], 0.)
733        for right_offset in [-1, -2, -3, -4]:
734          np.testing.assert_allclose(np_output[:, :, right_offset, :], 0.)
735        np.testing.assert_allclose(np_output[:, 1:-2, 3:-4, :], 1.)
736      elif data_format == 'channels_first':
737        for top_offset in [0]:
738          np.testing.assert_allclose(np_output[:, :, top_offset, :], 0.)
739        for bottom_offset in [-1, -2]:
740          np.testing.assert_allclose(np_output[:, :, bottom_offset, :], 0.)
741        for left_offset in [0, 1, 2]:
742          np.testing.assert_allclose(np_output[:, :, :, left_offset], 0.)
743        for right_offset in [-1, -2, -3, -4]:
744          np.testing.assert_allclose(np_output[:, :, :, right_offset], 0.)
745        np.testing.assert_allclose(np_output[:, :, 1:-2, 3:-4], 1.)
746
747    # test incorrect use
748    with self.assertRaises(ValueError):
749      keras.layers.ZeroPadding2D(padding=(1, 1, 1))
750    with self.assertRaises(ValueError):
751      keras.layers.ZeroPadding2D(padding=None)
752
753  @parameterized.named_parameters(('channels_first', 'channels_first'),
754                                  ('channels_last', 'channels_last'))
755  def test_zero_padding_3d(self, data_format):
756    num_samples = 2
757    stack_size = 2
758    input_len_dim1 = 4
759    input_len_dim2 = 5
760    input_len_dim3 = 3
761
762    if data_format == 'channels_first':
763      inputs = np.ones((num_samples, stack_size, input_len_dim1, input_len_dim2,
764                        input_len_dim3))
765    elif data_format == 'channels_last':
766      inputs = np.ones((num_samples, input_len_dim1, input_len_dim2,
767                        input_len_dim3, stack_size))
768
769    with self.cached_session():
770      # basic test
771      testing_utils.layer_test(
772          keras.layers.ZeroPadding3D,
773          kwargs={
774              'padding': (2, 2, 2),
775              'data_format': data_format
776          },
777          input_shape=inputs.shape)
778      testing_utils.layer_test(
779          keras.layers.ZeroPadding3D,
780          kwargs={
781              'padding': ((1, 2), (3, 4), (0, 2)),
782              'data_format': data_format
783          },
784          input_shape=inputs.shape)
785
786    with self.cached_session():
787      # correctness test
788      layer = keras.layers.ZeroPadding3D(
789          padding=(2, 2, 2), data_format=data_format)
790      layer.build(inputs.shape)
791      output = layer(keras.backend.variable(inputs))
792      if context.executing_eagerly():
793        np_output = output.numpy()
794      else:
795        np_output = keras.backend.eval(output)
796      if data_format == 'channels_last':
797        for offset in [0, 1, -1, -2]:
798          np.testing.assert_allclose(np_output[:, offset, :, :, :], 0.)
799          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
800          np.testing.assert_allclose(np_output[:, :, :, offset, :], 0.)
801        np.testing.assert_allclose(np_output[:, 2:-2, 2:-2, 2:-2, :], 1.)
802      elif data_format == 'channels_first':
803        for offset in [0, 1, -1, -2]:
804          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
805          np.testing.assert_allclose(np_output[:, :, :, offset, :], 0.)
806          np.testing.assert_allclose(np_output[:, :, :, :, offset], 0.)
807        np.testing.assert_allclose(np_output[:, :, 2:-2, 2:-2, 2:-2], 1.)
808
809      layer = keras.layers.ZeroPadding3D(
810          padding=((1, 2), (3, 4), (0, 2)), data_format=data_format)
811      layer.build(inputs.shape)
812      output = layer(keras.backend.variable(inputs))
813      if context.executing_eagerly():
814        np_output = output.numpy()
815      else:
816        np_output = keras.backend.eval(output)
817      if data_format == 'channels_last':
818        for offset in [0]:
819          np.testing.assert_allclose(np_output[:, offset, :, :, :], 0.)
820        for offset in [-1, -2]:
821          np.testing.assert_allclose(np_output[:, offset, :, :, :], 0.)
822        for offset in [0, 1, 2]:
823          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
824        for offset in [-1, -2, -3, -4]:
825          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
826        for offset in [-1, -2]:
827          np.testing.assert_allclose(np_output[:, :, :, offset, :], 0.)
828        np.testing.assert_allclose(np_output[:, 1:-2, 3:-4, 0:-2, :], 1.)
829      elif data_format == 'channels_first':
830        for offset in [0]:
831          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
832        for offset in [-1, -2]:
833          np.testing.assert_allclose(np_output[:, :, offset, :, :], 0.)
834        for offset in [0, 1, 2]:
835          np.testing.assert_allclose(np_output[:, :, :, offset, :], 0.)
836        for offset in [-1, -2, -3, -4]:
837          np.testing.assert_allclose(np_output[:, :, :, offset, :], 0.)
838        for offset in [-1, -2]:
839          np.testing.assert_allclose(np_output[:, :, :, :, offset], 0.)
840        np.testing.assert_allclose(np_output[:, :, 1:-2, 3:-4, 0:-2], 1.)
841
842    # test incorrect use
843    with self.assertRaises(ValueError):
844      keras.layers.ZeroPadding3D(padding=(1, 1))
845    with self.assertRaises(ValueError):
846      keras.layers.ZeroPadding3D(padding=None)
847
848
849@test_util.for_all_test_methods(test_util.disable_xla,
850                                'align_corners=False not supported by XLA')
851@keras_parameterized.run_all_keras_modes
852class UpSamplingTest(keras_parameterized.TestCase):
853
854  def test_upsampling_1d(self):
855    with self.cached_session():
856      testing_utils.layer_test(
857          keras.layers.UpSampling1D, kwargs={'size': 2}, input_shape=(3, 5, 4))
858
859  def test_upsampling_2d(self):
860    num_samples = 2
861    stack_size = 2
862    input_num_row = 11
863    input_num_col = 12
864
865    for data_format in ['channels_first', 'channels_last']:
866      if data_format == 'channels_first':
867        inputs = np.random.rand(num_samples, stack_size, input_num_row,
868                                input_num_col)
869      else:
870        inputs = np.random.rand(num_samples, input_num_row, input_num_col,
871                                stack_size)
872
873      # basic test
874      with self.cached_session():
875        testing_utils.layer_test(
876            keras.layers.UpSampling2D,
877            kwargs={'size': (2, 2),
878                    'data_format': data_format},
879            input_shape=inputs.shape)
880
881        for length_row in [2]:
882          for length_col in [2, 3]:
883            layer = keras.layers.UpSampling2D(
884                size=(length_row, length_col), data_format=data_format)
885            layer.build(inputs.shape)
886            output = layer(keras.backend.variable(inputs))
887            if context.executing_eagerly():
888              np_output = output.numpy()
889            else:
890              np_output = keras.backend.eval(output)
891            if data_format == 'channels_first':
892              assert np_output.shape[2] == length_row * input_num_row
893              assert np_output.shape[3] == length_col * input_num_col
894            else:  # tf
895              assert np_output.shape[1] == length_row * input_num_row
896              assert np_output.shape[2] == length_col * input_num_col
897
898            # compare with numpy
899            if data_format == 'channels_first':
900              expected_out = np.repeat(inputs, length_row, axis=2)
901              expected_out = np.repeat(expected_out, length_col, axis=3)
902            else:  # tf
903              expected_out = np.repeat(inputs, length_row, axis=1)
904              expected_out = np.repeat(expected_out, length_col, axis=2)
905
906            np.testing.assert_allclose(np_output, expected_out)
907
908  def test_upsampling_2d_bilinear(self):
909    num_samples = 2
910    stack_size = 2
911    input_num_row = 11
912    input_num_col = 12
913    for data_format in ['channels_first', 'channels_last']:
914      if data_format == 'channels_first':
915        inputs = np.random.rand(num_samples, stack_size, input_num_row,
916                                input_num_col)
917      else:
918        inputs = np.random.rand(num_samples, input_num_row, input_num_col,
919                                stack_size)
920
921      testing_utils.layer_test(keras.layers.UpSampling2D,
922                               kwargs={'size': (2, 2),
923                                       'data_format': data_format,
924                                       'interpolation': 'bilinear'},
925                               input_shape=inputs.shape)
926
927      if not context.executing_eagerly():
928        for length_row in [2]:
929          for length_col in [2, 3]:
930            layer = keras.layers.UpSampling2D(
931                size=(length_row, length_col),
932                data_format=data_format)
933            layer.build(inputs.shape)
934            outputs = layer(keras.backend.variable(inputs))
935            np_output = keras.backend.eval(outputs)
936            if data_format == 'channels_first':
937              self.assertEqual(np_output.shape[2], length_row * input_num_row)
938              self.assertEqual(np_output.shape[3], length_col * input_num_col)
939            else:
940              self.assertEqual(np_output.shape[1], length_row * input_num_row)
941              self.assertEqual(np_output.shape[2], length_col * input_num_col)
942
943  def test_upsampling_3d(self):
944    num_samples = 2
945    stack_size = 2
946    input_len_dim1 = 10
947    input_len_dim2 = 11
948    input_len_dim3 = 12
949
950    for data_format in ['channels_first', 'channels_last']:
951      if data_format == 'channels_first':
952        inputs = np.random.rand(num_samples, stack_size, input_len_dim1,
953                                input_len_dim2, input_len_dim3)
954      else:
955        inputs = np.random.rand(num_samples, input_len_dim1, input_len_dim2,
956                                input_len_dim3, stack_size)
957
958      # basic test
959      with self.cached_session():
960        testing_utils.layer_test(
961            keras.layers.UpSampling3D,
962            kwargs={'size': (2, 2, 2),
963                    'data_format': data_format},
964            input_shape=inputs.shape)
965
966        for length_dim1 in [2, 3]:
967          for length_dim2 in [2]:
968            for length_dim3 in [3]:
969              layer = keras.layers.UpSampling3D(
970                  size=(length_dim1, length_dim2, length_dim3),
971                  data_format=data_format)
972              layer.build(inputs.shape)
973              output = layer(keras.backend.variable(inputs))
974              if context.executing_eagerly():
975                np_output = output.numpy()
976              else:
977                np_output = keras.backend.eval(output)
978              if data_format == 'channels_first':
979                assert np_output.shape[2] == length_dim1 * input_len_dim1
980                assert np_output.shape[3] == length_dim2 * input_len_dim2
981                assert np_output.shape[4] == length_dim3 * input_len_dim3
982              else:  # tf
983                assert np_output.shape[1] == length_dim1 * input_len_dim1
984                assert np_output.shape[2] == length_dim2 * input_len_dim2
985                assert np_output.shape[3] == length_dim3 * input_len_dim3
986
987              # compare with numpy
988              if data_format == 'channels_first':
989                expected_out = np.repeat(inputs, length_dim1, axis=2)
990                expected_out = np.repeat(expected_out, length_dim2, axis=3)
991                expected_out = np.repeat(expected_out, length_dim3, axis=4)
992              else:  # tf
993                expected_out = np.repeat(inputs, length_dim1, axis=1)
994                expected_out = np.repeat(expected_out, length_dim2, axis=2)
995                expected_out = np.repeat(expected_out, length_dim3, axis=3)
996
997              np.testing.assert_allclose(np_output, expected_out)
998
999
1000@keras_parameterized.run_all_keras_modes
1001class CroppingTest(keras_parameterized.TestCase):
1002
1003  def test_cropping_1d(self):
1004    num_samples = 2
1005    time_length = 4
1006    input_len_dim1 = 2
1007    inputs = np.random.rand(num_samples, time_length, input_len_dim1)
1008
1009    with self.cached_session():
1010      testing_utils.layer_test(
1011          keras.layers.Cropping1D,
1012          kwargs={'cropping': (2, 2)},
1013          input_shape=inputs.shape)
1014
1015    # test incorrect use
1016    with self.assertRaises(ValueError):
1017      keras.layers.Cropping1D(cropping=(1, 1, 1))
1018    with self.assertRaises(ValueError):
1019      keras.layers.Cropping1D(cropping=None)
1020
1021  def test_cropping_2d(self):
1022    num_samples = 2
1023    stack_size = 2
1024    input_len_dim1 = 9
1025    input_len_dim2 = 9
1026    cropping = ((2, 2), (3, 3))
1027
1028    for data_format in ['channels_first', 'channels_last']:
1029      if data_format == 'channels_first':
1030        inputs = np.random.rand(num_samples, stack_size, input_len_dim1,
1031                                input_len_dim2)
1032      else:
1033        inputs = np.random.rand(num_samples, input_len_dim1, input_len_dim2,
1034                                stack_size)
1035      with self.cached_session():
1036        # basic test
1037        testing_utils.layer_test(
1038            keras.layers.Cropping2D,
1039            kwargs={'cropping': cropping,
1040                    'data_format': data_format},
1041            input_shape=inputs.shape)
1042        # correctness test
1043        layer = keras.layers.Cropping2D(
1044            cropping=cropping, data_format=data_format)
1045        layer.build(inputs.shape)
1046        output = layer(keras.backend.variable(inputs))
1047        if context.executing_eagerly():
1048          np_output = output.numpy()
1049        else:
1050          np_output = keras.backend.eval(output)
1051        # compare with numpy
1052        if data_format == 'channels_first':
1053          expected_out = inputs[:, :, cropping[0][0]:-cropping[0][1], cropping[
1054              1][0]:-cropping[1][1]]
1055        else:
1056          expected_out = inputs[:, cropping[0][0]:-cropping[0][1], cropping[1][
1057              0]:-cropping[1][1], :]
1058        np.testing.assert_allclose(np_output, expected_out)
1059
1060    for data_format in ['channels_first', 'channels_last']:
1061      if data_format == 'channels_first':
1062        inputs = np.random.rand(num_samples, stack_size, input_len_dim1,
1063                                input_len_dim2)
1064      else:
1065        inputs = np.random.rand(num_samples, input_len_dim1, input_len_dim2,
1066                                stack_size)
1067      # another correctness test (no cropping)
1068      with self.cached_session():
1069        cropping = ((0, 0), (0, 0))
1070        layer = keras.layers.Cropping2D(
1071            cropping=cropping, data_format=data_format)
1072        layer.build(inputs.shape)
1073        output = layer(keras.backend.variable(inputs))
1074        if context.executing_eagerly():
1075          np_output = output.numpy()
1076        else:
1077          np_output = keras.backend.eval(output)
1078        # compare with input
1079        np.testing.assert_allclose(np_output, inputs)
1080
1081    # test incorrect use
1082    with self.assertRaises(ValueError):
1083      keras.layers.Cropping2D(cropping=(1, 1, 1))
1084    with self.assertRaises(ValueError):
1085      keras.layers.Cropping2D(cropping=None)
1086
1087  def test_cropping_3d(self):
1088    num_samples = 2
1089    stack_size = 2
1090    input_len_dim1 = 8
1091    input_len_dim2 = 8
1092    input_len_dim3 = 8
1093    croppings = [((2, 2), (1, 1), (2, 3)), 3, (0, 1, 1)]
1094
1095    for cropping in croppings:
1096      for data_format in ['channels_last', 'channels_first']:
1097        if data_format == 'channels_first':
1098          inputs = np.random.rand(num_samples, stack_size, input_len_dim1,
1099                                  input_len_dim2, input_len_dim3)
1100        else:
1101          inputs = np.random.rand(num_samples, input_len_dim1, input_len_dim2,
1102                                  input_len_dim3, stack_size)
1103        # basic test
1104        with self.cached_session():
1105          testing_utils.layer_test(
1106              keras.layers.Cropping3D,
1107              kwargs={'cropping': cropping,
1108                      'data_format': data_format},
1109              input_shape=inputs.shape)
1110
1111        if len(croppings) == 3 and len(croppings[0]) == 2:
1112          # correctness test
1113          with self.cached_session():
1114            layer = keras.layers.Cropping3D(
1115                cropping=cropping, data_format=data_format)
1116            layer.build(inputs.shape)
1117            output = layer(keras.backend.variable(inputs))
1118            if context.executing_eagerly():
1119              np_output = output.numpy()
1120            else:
1121              np_output = keras.backend.eval(output)
1122            # compare with numpy
1123            if data_format == 'channels_first':
1124              expected_out = inputs[:, :,
1125                                    cropping[0][0]:-cropping[0][1],
1126                                    cropping[1][0]:-cropping[1][1],
1127                                    cropping[2][0]:-cropping[2][1]]
1128            else:
1129              expected_out = inputs[:,
1130                                    cropping[0][0]:-cropping[0][1],
1131                                    cropping[1][0]:-cropping[1][1],
1132                                    cropping[2][0]:-cropping[2][1], :]
1133            np.testing.assert_allclose(np_output, expected_out)
1134
1135    # test incorrect use
1136    with self.assertRaises(ValueError):
1137      keras.layers.Cropping3D(cropping=(1, 1))
1138    with self.assertRaises(ValueError):
1139      keras.layers.Cropping3D(cropping=None)
1140
1141
1142@keras_parameterized.run_all_keras_modes
1143class DepthwiseConv2DTest(keras_parameterized.TestCase):
1144
1145  def _run_test(self, kwargs, expected_output_shape=None):
1146    num_samples = 2
1147    stack_size = 3
1148    num_row = 7
1149    num_col = 6
1150
1151    with self.cached_session():
1152      testing_utils.layer_test(
1153          keras.layers.DepthwiseConv2D,
1154          kwargs=kwargs,
1155          input_shape=(num_samples, num_row, num_col, stack_size),
1156          expected_output_shape=expected_output_shape)
1157
1158  @parameterized.named_parameters(
1159      ('padding_valid', {'padding': 'valid'}),
1160      ('padding_same', {'padding': 'same'}),
1161      ('strides', {'strides': (2, 2)}),
1162      # Only runs on GPU with CUDA, channels_first is not supported on CPU.
1163      # TODO(b/62340061): Support channels_first on CPU.
1164      ('data_format', {'data_format': 'channels_first'}),
1165      ('depth_multiplier_1', {'depth_multiplier': 1}),
1166      ('depth_multiplier_2', {'depth_multiplier': 2}),
1167      ('dilation_rate', {'dilation_rate': (2, 2)}, (None, 3, 2, 3)),
1168  )
1169  def test_depthwise_conv2d(self, kwargs, expected_output_shape=None):
1170    kwargs['kernel_size'] = (3, 3)
1171    if 'data_format' not in kwargs or test.is_gpu_available(cuda_only=True):
1172      self._run_test(kwargs, expected_output_shape)
1173
1174  def test_depthwise_conv2d_full(self):
1175    kwargs = {
1176        'kernel_size': 3,
1177        'padding': 'valid',
1178        'data_format': 'channels_last',
1179        'dilation_rate': (1, 1),
1180        'activation': None,
1181        'depthwise_regularizer': 'l2',
1182        'bias_regularizer': 'l2',
1183        'activity_regularizer': 'l2',
1184        'depthwise_constraint': 'unit_norm',
1185        'use_bias': True,
1186        'strides': (2, 2),
1187        'depth_multiplier': 1,
1188    }
1189    self._run_test(kwargs)
1190
1191if __name__ == '__main__':
1192  test.main()
1193