Home | History | Annotate | Download | only in kernel_tests
      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 """Functional tests for morphological filtering operations."""
     16 
     17 from __future__ import absolute_import
     18 from __future__ import division
     19 from __future__ import print_function
     20 
     21 import numpy as np
     22 
     23 from tensorflow.python.framework import constant_op
     24 from tensorflow.python.ops import gradient_checker
     25 from tensorflow.python.ops import nn_ops
     26 import tensorflow.python.ops.nn_grad  # pylint: disable=unused-import
     27 from tensorflow.python.platform import test
     28 
     29 
     30 class DilationTest(test.TestCase):
     31 
     32   def _VerifyValues(self, image, kernel, strides, rates, padding, out, use_gpu):
     33     """Verifies the output values of the dilation function.
     34 
     35     Args:
     36       image: Input tensor with shape: [batch, in_height, in_width, channels].
     37       kernel: Filter tensor with shape: [filter_height, filter_width, channels].
     38       strides: Output strides, specified as [stride_height, stride_width].
     39       rates: Atrous rates, specified as [rate_height, rate_width].
     40       padding: Padding type.
     41       out: Expected output.
     42       use_gpu: Whether we are running on GPU.
     43     """
     44     strides = [1] + strides + [1]
     45     rates = [1] + rates + [1]
     46 
     47     with self.test_session(use_gpu=use_gpu):
     48       out_tensor = nn_ops.dilation2d(
     49           constant_op.constant(image),
     50           constant_op.constant(kernel),
     51           strides=strides,
     52           rates=rates,
     53           padding=padding,
     54           name="dilation2d")
     55       self.assertAllClose(out, out_tensor.eval())
     56 
     57   def _testDilationValidPadding(self, use_gpu):
     58     # [1, 2, 2, 1]
     59     image = [[[[.1], [.2]], [[.3], [.4]]]]
     60     # [2, 2, 1]
     61     kernel = [[[.4], [.3]], [[.1], [.0]]]
     62     # [1, 1, 1, 1]
     63     out = [[[[.5]]]]
     64     self._VerifyValues(
     65         image,
     66         kernel,
     67         strides=[1, 1],
     68         rates=[1, 1],
     69         padding="VALID",
     70         out=out,
     71         use_gpu=use_gpu)
     72 
     73   def _testDilationSamePadding(self, use_gpu):
     74     # [1, 2, 2, 1]
     75     image = [[[[.1], [.2]], [[.3], [.4]]]]
     76     # [2, 2, 1]
     77     kernel = [[[.4], [.3]], [[.1], [.0]]]
     78     # [1, 2, 2, 1]
     79     out = [[[[.5], [.6]], [[.7], [.8]]]]
     80     self._VerifyValues(
     81         image,
     82         kernel,
     83         strides=[1, 1],
     84         rates=[1, 1],
     85         padding="SAME",
     86         out=out,
     87         use_gpu=use_gpu)
     88 
     89   def _testDilationSamePaddingDepth(self, use_gpu):
     90     # [1, 2, 2, 3]
     91     image = [[[[.1, .2, .0], [.2, .3, .1]], [[.3, .4, .2], [.4, .5, .3]]]]
     92     # [2, 2, 3]
     93     kernel = [[[.4, .5, .3], [.3, .4, .2]], [[.1, .2, .0], [.0, .1, -.1]]]
     94     # [1, 2, 2, 3]
     95     out = [[[[.5, .7, .3], [.6, .8, .4]], [[.7, .9, .5], [.8, 1., .6]]]]
     96     self._VerifyValues(
     97         image,
     98         kernel,
     99         strides=[1, 1],
    100         rates=[1, 1],
    101         padding="SAME",
    102         out=out,
    103         use_gpu=use_gpu)
    104 
    105   def _testDilationSamePaddingBatch(self, use_gpu):
    106     # [2, 2, 2, 1]
    107     image = [[[[.1], [.2]], [[.3], [.4]]], [[[.2], [.3]], [[.4], [.5]]]]
    108     # [2, 2, 1]
    109     kernel = [[[.4], [.3]], [[.1], [.0]]]
    110     # [2, 2, 2, 1]
    111     out = [[[[.5], [.6]], [[.7], [.8]]], [[[.6], [.7]], [[.8], [.9]]]]
    112     self._VerifyValues(
    113         image,
    114         kernel,
    115         strides=[1, 1],
    116         rates=[1, 1],
    117         padding="SAME",
    118         out=out,
    119         use_gpu=use_gpu)
    120 
    121   def _testDilationValidPaddingNonSquareWindow(self, use_gpu):
    122     # [1, 2, 2, 1]
    123     image = [[[[.1], [.2]], [[.3], [.4]]]]
    124     # [1, 2, 1]
    125     kernel = [[[.4], [.3]]]
    126     # [1, 2, 1, 1]
    127     out = [[[[.5]], [[.7]]]]
    128     self._VerifyValues(
    129         image,
    130         kernel,
    131         strides=[1, 1],
    132         rates=[1, 1],
    133         padding="VALID",
    134         out=out,
    135         use_gpu=use_gpu)
    136 
    137   def _testDilationSamePaddingRate(self, use_gpu):
    138     # [1, 3, 3, 1]
    139     image = [[[[.1], [.2], [.3]], [[.4], [.5], [.6]], [[.7], [.8], [.9]]]]
    140     # [2, 2, 1]
    141     kernel = [[[.4], [.3]], [[.1], [.2]]]
    142     # Because rate = 2, the effective kernel is [3, 3, 1]:
    143     # kernel_eff = [[[.4], [.0], [.3]],
    144     #               [[.0], [.0], [.0]],
    145     #               [[.1], [.0], [.2]]]
    146     # [1, 3, 3, 1]
    147     out = [[[[.7], [.8], [.6]], [[1.0], [1.1], [.9]], [[.8], [.9], [.9]]]]
    148     self._VerifyValues(
    149         image,
    150         kernel,
    151         strides=[1, 1],
    152         rates=[2, 2],
    153         padding="SAME",
    154         out=out,
    155         use_gpu=use_gpu)
    156 
    157   def _testDilationValidPaddingUnevenStride(self, use_gpu):
    158     # [1, 3, 3, 1]
    159     image = [[[[.1], [.2], [.3], [.4]], [[.5], [.6], [.7], [.8]],
    160               [[.9], [1.0], [1.1], [1.2]]]]
    161     # [2, 2, 1]
    162     kernel = [[[.4], [.3]], [[.1], [.2]]]
    163     # [1, 2, 2, 1]
    164     out = [[[[.8], [1.0]], [[1.2], [1.4]]]]
    165     self._VerifyValues(
    166         image,
    167         kernel,
    168         strides=[1, 2],
    169         rates=[1, 1],
    170         padding="VALID",
    171         out=out,
    172         use_gpu=use_gpu)
    173 
    174   def testDilation(self):
    175     for use_gpu in True, False:
    176       self._testDilationValidPadding(use_gpu)
    177       self._testDilationSamePadding(use_gpu)
    178       self._testDilationSamePaddingDepth(use_gpu)
    179       self._testDilationSamePaddingBatch(use_gpu)
    180       self._testDilationValidPaddingNonSquareWindow(use_gpu)
    181       self._testDilationSamePaddingRate(use_gpu)
    182       self._testDilationValidPaddingUnevenStride(use_gpu)
    183 
    184   def _ConstructAndTestGradient(self, image_shape, kernel_shape, strides, rates,
    185                                 padding, use_gpu):
    186     """Verifies the gradients of the dilation function.
    187 
    188     Args:
    189       image_shape: Input shape, [batch, in_height, in_width, channels].
    190       kernel_shape: Filter shape, [filter_height, filter_width, channels].
    191       strides: Output strides, specified as [stride_height, stride_width].
    192       rates: Atrous rates, specified as [rate_height, rate_width].
    193       padding: Padding type.
    194       use_gpu: Whether we are running on GPU.
    195     """
    196     assert image_shape[3] == kernel_shape[2]
    197 
    198     np.random.seed(1)  # Make it reproducible.
    199     image = np.random.random_sample(image_shape).astype(np.float32)
    200     kernel = np.random.random_sample(kernel_shape).astype(np.float32)
    201     image_init = np.random.random_sample(image_shape).astype(np.float32)
    202     kernel_init = np.random.random_sample(kernel_shape).astype(np.float32)
    203 
    204     strides = [1] + strides + [1]
    205     rates = [1] + rates + [1]
    206 
    207     with self.test_session(use_gpu=use_gpu):
    208       image_tensor = constant_op.constant(
    209           image, shape=image_shape, name="input")
    210       kernel_tensor = constant_op.constant(
    211           kernel, shape=kernel_shape, name="filter")
    212       out_tensor = nn_ops.dilation2d(
    213           image_tensor,
    214           kernel_tensor,
    215           strides=strides,
    216           rates=rates,
    217           padding=padding,
    218           name="dilation2d")
    219       out_shape = out_tensor.eval().shape
    220 
    221       # Small delta is necessary for argmax to remain the same.
    222       err = gradient_checker.compute_gradient_error(
    223           [image_tensor, kernel_tensor], [image_shape, kernel_shape],
    224           out_tensor,
    225           out_shape, [image_init, kernel_init],
    226           delta=1e-3)
    227 
    228     print("Dilation gradient error = %f" % err)
    229     self.assertLess(err, 1e-4)
    230 
    231   def _testDilationGradValidPadding_1x1x1(self, use_gpu):
    232     self._ConstructAndTestGradient(
    233         image_shape=[1, 3, 3, 1],
    234         kernel_shape=[1, 1, 1],
    235         strides=[1, 1],
    236         rates=[1, 1],
    237         padding="VALID",
    238         use_gpu=use_gpu)
    239 
    240   def _testDilationGradSamePadding_1x1x1(self, use_gpu):
    241     self._ConstructAndTestGradient(
    242         image_shape=[1, 3, 3, 1],
    243         kernel_shape=[1, 1, 1],
    244         strides=[1, 1],
    245         rates=[1, 1],
    246         padding="SAME",
    247         use_gpu=use_gpu)
    248 
    249   def _testDilationGradSamePadding_1x1x2(self, use_gpu):
    250     self._ConstructAndTestGradient(
    251         image_shape=[1, 3, 3, 2],
    252         kernel_shape=[1, 1, 2],
    253         strides=[1, 1],
    254         rates=[1, 1],
    255         padding="SAME",
    256         use_gpu=use_gpu)
    257 
    258   def _testDilationGradValidPadding_2x2x1(self, use_gpu):
    259     self._ConstructAndTestGradient(
    260         image_shape=[1, 3, 3, 1],
    261         kernel_shape=[2, 2, 1],
    262         strides=[1, 1],
    263         rates=[1, 1],
    264         padding="VALID",
    265         use_gpu=use_gpu)
    266 
    267   def _testDilationGradSamePadding_2x2x1(self, use_gpu):
    268     self._ConstructAndTestGradient(
    269         image_shape=[1, 3, 3, 1],
    270         kernel_shape=[2, 2, 1],
    271         strides=[1, 1],
    272         rates=[1, 1],
    273         padding="SAME",
    274         use_gpu=use_gpu)
    275 
    276   def _testDilationGradSamePaddingBatch_2x2x1(self, use_gpu):
    277     self._ConstructAndTestGradient(
    278         image_shape=[4, 3, 3, 1],
    279         kernel_shape=[2, 2, 1],
    280         strides=[1, 1],
    281         rates=[1, 1],
    282         padding="SAME",
    283         use_gpu=use_gpu)
    284 
    285   def _testDilationGradSamePadding_2x2x4(self, use_gpu):
    286     self._ConstructAndTestGradient(
    287         image_shape=[1, 3, 3, 4],
    288         kernel_shape=[2, 2, 4],
    289         strides=[1, 1],
    290         rates=[1, 1],
    291         padding="SAME",
    292         use_gpu=use_gpu)
    293 
    294   def testDilationGrad(self):
    295     for use_gpu in True, False:
    296       self._testDilationGradValidPadding_1x1x1(use_gpu)
    297       self._testDilationGradSamePadding_1x1x1(use_gpu)
    298       self._testDilationGradSamePadding_1x1x2(use_gpu)
    299       self._testDilationGradValidPadding_2x2x1(use_gpu)
    300       self._testDilationGradSamePadding_2x2x1(use_gpu)
    301       self._testDilationGradSamePaddingBatch_2x2x1(use_gpu)
    302       self._testDilationGradSamePadding_2x2x4(use_gpu)
    303 
    304 
    305 class ErosionTest(test.TestCase):
    306 
    307   def _VerifyValues(self, image, kernel, strides, rates, padding, out, use_gpu):
    308     """Verifies the output values of the erosion function.
    309 
    310     Args:
    311       image: Input tensor with shape: [batch, in_height, in_width, channels].
    312       kernel: Filter tensor with shape: [filter_height, filter_width, channels].
    313       strides: Output strides, specified as [stride_height, stride_width].
    314       rates: Atrous rates, specified as [rate_height, rate_width].
    315       padding: Padding type.
    316       out: Expected output.
    317       use_gpu: Whether we are running on GPU.
    318     """
    319     strides = [1] + strides + [1]
    320     rates = [1] + rates + [1]
    321 
    322     with self.test_session(use_gpu=use_gpu):
    323       out_tensor = nn_ops.erosion2d(
    324           constant_op.constant(image),
    325           constant_op.constant(kernel),
    326           strides=strides,
    327           rates=rates,
    328           padding=padding,
    329           name="erosion2d")
    330       self.assertAllClose(out, out_tensor.eval())
    331 
    332   def _testErosionValidPadding(self, use_gpu):
    333     # [1, 2, 2, 1]
    334     image = [[[[.1], [.2]], [[.3], [.4]]]]
    335     # [2, 2, 1]
    336     kernel = [[[.4], [.3]], [[.1], [.0]]]
    337     # [1, 1, 1, 1]
    338     out = [[[[.0]]]]
    339     self._VerifyValues(
    340         image,
    341         kernel,
    342         strides=[1, 1],
    343         rates=[1, 1],
    344         padding="VALID",
    345         out=out,
    346         use_gpu=use_gpu)
    347 
    348   def _testErosionSamePadding(self, use_gpu):
    349     # [1, 2, 2, 1]
    350     image = [[[[.1], [.2]], [[.3], [.4]]]]
    351     # [2, 2, 1]
    352     kernel = [[[.4], [.3]], [[.1], [.0]]]
    353     # [1, 2, 2, 1]
    354     out = [[[[.0], [.1]], [[.3], [.4]]]]
    355     self._VerifyValues(
    356         image,
    357         kernel,
    358         strides=[1, 1],
    359         rates=[1, 1],
    360         padding="SAME",
    361         out=out,
    362         use_gpu=use_gpu)
    363 
    364   def _testErosionSamePaddingDepth(self, use_gpu):
    365     # [1, 2, 2, 3]
    366     image = [[[[.1, .2, .0], [.2, .3, .1]], [[.3, .4, .2], [.4, .5, .3]]]]
    367     # [2, 2, 3]
    368     kernel = [[[.4, .5, .3], [.3, .4, .2]], [[.1, .2, .0], [.0, .1, -.1]]]
    369     # [1, 2, 2, 3]
    370     out = [[[[.0, .0, .0], [.1, .1, .1]], [[.3, .3, .3], [.4, .4, .4]]]]
    371     self._VerifyValues(
    372         image,
    373         kernel,
    374         strides=[1, 1],
    375         rates=[1, 1],
    376         padding="SAME",
    377         out=out,
    378         use_gpu=use_gpu)
    379 
    380   def _testErosionSamePaddingBatch(self, use_gpu):
    381     # [2, 2, 2, 1]
    382     image = [[[[.1], [.2]], [[.3], [.4]]], [[[.2], [.3]], [[.4], [.5]]]]
    383     # [2, 2, 1]
    384     kernel = [[[.4], [.3]], [[.1], [.0]]]
    385     # [2, 2, 2, 1]
    386     out = [[[[.0], [.1]], [[.3], [.4]]], [[[.1], [.2]], [[.4], [.5]]]]
    387     self._VerifyValues(
    388         image,
    389         kernel,
    390         strides=[1, 1],
    391         rates=[1, 1],
    392         padding="SAME",
    393         out=out,
    394         use_gpu=use_gpu)
    395 
    396   def _testErosionValidPaddingNonSquareWindow(self, use_gpu):
    397     # [1, 2, 2, 1]
    398     image = [[[[.1], [.2]], [[.3], [.4]]]]
    399     # [1, 2, 1]
    400     kernel = [[[.4], [.3]]]
    401     # [1, 2, 1, 1]
    402     out = [[[[-.2]], [[.0]]]]
    403     self._VerifyValues(
    404         image,
    405         kernel,
    406         strides=[1, 1],
    407         rates=[1, 1],
    408         padding="VALID",
    409         out=out,
    410         use_gpu=use_gpu)
    411 
    412   def _testErosionSamePaddingRate(self, use_gpu):
    413     # [1, 3, 3, 1]
    414     image = [[[[.1], [.2], [.3]], [[.4], [.5], [.6]], [[.7], [.8], [.9]]]]
    415     # [2, 2, 1]
    416     kernel = [[[.4], [.3]], [[.1], [.2]]]
    417     # Because rate = 2, the effective kernel is [3, 3, 1]:
    418     # kernel_eff = [[[.4], [.0], [.3]],
    419     #               [[.0], [.0], [.0]],
    420     #               [[.1], [.0], [.2]]]
    421     # [1, 3, 3, 1]
    422     out = [[[[.1], [.1], [.2]], [[0.1], [-.1], [.0]], [[.4], [.2], [.3]]]]
    423     self._VerifyValues(
    424         image,
    425         kernel,
    426         strides=[1, 1],
    427         rates=[2, 2],
    428         padding="SAME",
    429         out=out,
    430         use_gpu=use_gpu)
    431 
    432   def _testErosionValidPaddingUnevenStride(self, use_gpu):
    433     # [1, 3, 3, 1]
    434     image = [[[[.1], [.2], [.3], [.4]], [[.5], [.6], [.7], [.8]],
    435               [[.9], [1.0], [1.1], [1.2]]]]
    436     # [2, 2, 1]
    437     kernel = [[[.4], [.3]], [[.1], [.2]]]
    438     # [1, 2, 2, 1]
    439     out = [[[[-.1], [.1]], [[.3], [.5]]]]
    440     self._VerifyValues(
    441         image,
    442         kernel,
    443         strides=[1, 2],
    444         rates=[1, 1],
    445         padding="VALID",
    446         out=out,
    447         use_gpu=use_gpu)
    448 
    449   def testErosion(self):
    450     for use_gpu in True, False:
    451       self._testErosionValidPadding(use_gpu)
    452       self._testErosionSamePadding(use_gpu)
    453       self._testErosionSamePaddingDepth(use_gpu)
    454       self._testErosionSamePaddingBatch(use_gpu)
    455       self._testErosionValidPaddingNonSquareWindow(use_gpu)
    456       self._testErosionSamePaddingRate(use_gpu)
    457       self._testErosionValidPaddingUnevenStride(use_gpu)
    458 
    459   def _ConstructAndTestGradient(self, image_shape, kernel_shape, strides, rates,
    460                                 padding, use_gpu):
    461     """Verifies the gradients of the erosion function.
    462 
    463     Args:
    464       image_shape: Input shape, [batch, in_height, in_width, channels].
    465       kernel_shape: Filter shape, [filter_height, filter_width, channels].
    466       strides: Output strides, specified as [stride_height, stride_width].
    467       rates: Atrous rates, specified as [rate_height, rate_width].
    468       padding: Padding type.
    469       use_gpu: Whether we are running on GPU.
    470     """
    471     assert image_shape[3] == kernel_shape[2]
    472 
    473     np.random.seed(1)  # Make it reproducible.
    474     image = np.random.random_sample(image_shape).astype(np.float32)
    475     kernel = np.random.random_sample(kernel_shape).astype(np.float32)
    476     image_init = np.random.random_sample(image_shape).astype(np.float32)
    477     kernel_init = np.random.random_sample(kernel_shape).astype(np.float32)
    478 
    479     strides = [1] + strides + [1]
    480     rates = [1] + rates + [1]
    481 
    482     with self.test_session(use_gpu=use_gpu):
    483       image_tensor = constant_op.constant(
    484           image, shape=image_shape, name="input")
    485       kernel_tensor = constant_op.constant(
    486           kernel, shape=kernel_shape, name="filter")
    487       out_tensor = nn_ops.erosion2d(
    488           image_tensor,
    489           kernel_tensor,
    490           strides=strides,
    491           rates=rates,
    492           padding=padding,
    493           name="erosion2d")
    494       out_shape = out_tensor.eval().shape
    495 
    496       # Small delta is necessary for argmax to remain the same.
    497       err = gradient_checker.compute_gradient_error(
    498           [image_tensor, kernel_tensor], [image_shape, kernel_shape],
    499           out_tensor,
    500           out_shape, [image_init, kernel_init],
    501           delta=1e-3)
    502 
    503     print("Erosion gradient error = %f" % err)
    504     self.assertLess(err, 1e-4)
    505 
    506   def _testErosionGradValidPadding_1x1x1(self, use_gpu):
    507     self._ConstructAndTestGradient(
    508         image_shape=[1, 3, 3, 1],
    509         kernel_shape=[1, 1, 1],
    510         strides=[1, 1],
    511         rates=[1, 1],
    512         padding="VALID",
    513         use_gpu=use_gpu)
    514 
    515   def _testErosionGradSamePadding_1x1x1(self, use_gpu):
    516     self._ConstructAndTestGradient(
    517         image_shape=[1, 3, 3, 1],
    518         kernel_shape=[1, 1, 1],
    519         strides=[1, 1],
    520         rates=[1, 1],
    521         padding="SAME",
    522         use_gpu=use_gpu)
    523 
    524   def _testErosionGradSamePadding_1x1x2(self, use_gpu):
    525     self._ConstructAndTestGradient(
    526         image_shape=[1, 3, 3, 2],
    527         kernel_shape=[1, 1, 2],
    528         strides=[1, 1],
    529         rates=[1, 1],
    530         padding="SAME",
    531         use_gpu=use_gpu)
    532 
    533   def _testErosionGradValidPadding_2x2x1(self, use_gpu):
    534     self._ConstructAndTestGradient(
    535         image_shape=[1, 3, 3, 1],
    536         kernel_shape=[2, 2, 1],
    537         strides=[1, 1],
    538         rates=[1, 1],
    539         padding="VALID",
    540         use_gpu=use_gpu)
    541 
    542   def _testErosionGradSamePadding_2x2x1(self, use_gpu):
    543     self._ConstructAndTestGradient(
    544         image_shape=[1, 3, 3, 1],
    545         kernel_shape=[2, 2, 1],
    546         strides=[1, 1],
    547         rates=[1, 1],
    548         padding="SAME",
    549         use_gpu=use_gpu)
    550 
    551   def _testErosionGradSamePaddingBatch_2x2x1(self, use_gpu):
    552     self._ConstructAndTestGradient(
    553         image_shape=[4, 3, 3, 1],
    554         kernel_shape=[2, 2, 1],
    555         strides=[1, 1],
    556         rates=[1, 1],
    557         padding="SAME",
    558         use_gpu=use_gpu)
    559 
    560   def _testErosionGradSamePadding_2x2x4(self, use_gpu):
    561     self._ConstructAndTestGradient(
    562         image_shape=[1, 3, 3, 4],
    563         kernel_shape=[2, 2, 4],
    564         strides=[1, 1],
    565         rates=[1, 1],
    566         padding="SAME",
    567         use_gpu=use_gpu)
    568 
    569   def testErosionGrad(self):
    570     for use_gpu in True, False:
    571       self._testErosionGradValidPadding_1x1x1(use_gpu)
    572       self._testErosionGradSamePadding_1x1x1(use_gpu)
    573       self._testErosionGradSamePadding_1x1x2(use_gpu)
    574       self._testErosionGradValidPadding_2x2x1(use_gpu)
    575       self._testErosionGradSamePadding_2x2x1(use_gpu)
    576       self._testErosionGradSamePaddingBatch_2x2x1(use_gpu)
    577       self._testErosionGradSamePadding_2x2x4(use_gpu)
    578 
    579 
    580 if __name__ == "__main__":
    581   test.main()
    582