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 scan ops."""
     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.framework import dtypes
     25 from tensorflow.python.framework import errors_impl
     26 from tensorflow.python.framework import ops
     27 from tensorflow.python.ops import gradient_checker
     28 from tensorflow.python.ops import math_ops
     29 from tensorflow.python.platform import test
     30 
     31 
     32 def numpy_reverse(x, axis):
     33   length = len(x.shape)
     34   if axis < 0:
     35     axis = length + axis
     36 
     37   ix = [
     38       slice(None, None, -1) if i == axis else slice(None) for i in range(length)
     39   ]
     40   return x[ix]
     41 
     42 
     43 def handle_options(func, x, axis, exclusive, reverse):
     44   """Adds tf options to numpy scan ops."""
     45   length = len(x.shape)
     46   if axis < 0:
     47     axis = length + axis
     48 
     49   if reverse:
     50     x = numpy_reverse(x, axis)
     51 
     52   if exclusive:
     53     ix_head = [slice(0, 1) if i == axis else slice(None) for i in range(length)]
     54     ix_init = [
     55         slice(0, -1) if i == axis else slice(None) for i in range(length)
     56     ]
     57     if func == np.cumsum:
     58       init = np.zeros_like(x[ix_head])
     59     elif func == np.cumprod:
     60       init = np.ones_like(x[ix_head])
     61     else:
     62       raise ValueError("Unknown scan function.")
     63     x = np.concatenate([init, func(x[ix_init], axis)], axis=axis)
     64   else:
     65     x = func(x, axis=axis)
     66 
     67   if reverse:
     68     x = numpy_reverse(x, axis)
     69   return x
     70 
     71 
     72 class CumsumTest(test.TestCase):
     73 
     74   valid_dtypes = [
     75       np.int32, np.int64, np.float16, np.float32, np.float64, np.complex64,
     76       np.complex128
     77   ]
     78 
     79   def _compare(self, x, axis, exclusive, reverse):
     80     np_out = handle_options(np.cumsum, x, axis, exclusive, reverse)
     81     with self.test_session(use_gpu=True):
     82       tf_out = math_ops.cumsum(x, axis, exclusive, reverse).eval()
     83 
     84     self.assertAllClose(np_out, tf_out)
     85 
     86   def _compareAll(self, x, axis):
     87     for exclusive in [True, False]:
     88       for reverse in [True, False]:
     89         self._compare(x, axis, exclusive, reverse)
     90 
     91   def testEmpty(self):
     92     for dtype in self.valid_dtypes:
     93       x = np.zeros([0]).astype(dtype)
     94       for axis in (-1, 0):
     95         self._compareAll(x, axis)
     96 
     97   def testAxisType(self):
     98     for dtype in self.valid_dtypes:
     99       x = np.arange(1, 6).reshape([5]).astype(dtype)
    100       for axis_dtype in [dtypes.int64, dtypes.int32]:
    101         with self.test_session(use_gpu=True):
    102           axis = constant_op.constant(0, axis_dtype)
    103           tf_out = math_ops.cumsum(x, axis).eval()
    104 
    105   def test1D(self):
    106     for dtype in self.valid_dtypes:
    107       x = np.arange(1, 6).reshape([5]).astype(dtype)
    108       for axis in (-1, 0):
    109         self._compareAll(x, axis)
    110 
    111   def test2D(self):
    112     for dtype in self.valid_dtypes:
    113       x = np.arange(0, 10).reshape([2, 5]).astype(dtype)
    114       for axis in (-2, -1, 0, 1):
    115         self._compareAll(x, axis)
    116 
    117   def test3D(self):
    118     for dtype in self.valid_dtypes:
    119       x = np.arange(0, 20).reshape([2, 2, 5]).astype(dtype)
    120       for axis in (-3, -2, -1, 0, 1, 2):
    121         self._compareAll(x, axis)
    122 
    123   def test6D(self):
    124     for dtype in self.valid_dtypes:
    125       x = np.arange(1, 145).reshape([2, 2, 3, 3, 2, 2]).astype(dtype)
    126       for axis in range(-6, 6, 3):
    127         self._compareAll(x, axis)
    128 
    129   def testInvalidAxis(self):
    130     x = np.arange(0, 10).reshape([2, 5]).astype(np.float32)
    131     input_tensor = ops.convert_to_tensor(x)
    132     with self.test_session(use_gpu=True):
    133       with self.assertRaisesWithPredicateMatch(
    134           errors_impl.InvalidArgumentError,
    135           lambda e: "Expected scan axis in the range [-2, 2)" in str(e)):
    136         math_ops.cumsum(input_tensor, -3).eval()
    137       with self.assertRaisesWithPredicateMatch(
    138           errors_impl.InvalidArgumentError,
    139           lambda e: "Expected scan axis in the range [-2, 2)" in str(e)):
    140         math_ops.cumsum(input_tensor, 2).eval()
    141       with self.assertRaisesWithPredicateMatch(
    142           errors_impl.InvalidArgumentError,
    143           lambda e: "axis must be a scalar" in str(e)):
    144         math_ops.cumsum(input_tensor, [0]).eval()
    145 
    146   def _compareGradient(self, shape, axis, exclusive, reverse):
    147     x = np.arange(0, 50).reshape(shape).astype(np.float64)
    148     with self.test_session(use_gpu=True):
    149       t = ops.convert_to_tensor(x)
    150       result = math_ops.cumsum(t, axis, exclusive, reverse)
    151       jacob_t, jacob_n = gradient_checker.compute_gradient(
    152           t, shape, result, shape, x_init_value=x, delta=1)
    153     self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8)
    154 
    155   def testGradient(self):
    156     for axis in (-1, 0):
    157       self._compareGradient([50], axis, False, False)
    158 
    159   def testGradientReverse(self):
    160     for axis in (-1, 0):
    161       self._compareGradient([50], axis, False, True)
    162 
    163   def testGradientExclusive(self):
    164     for axis in (-1, 0):
    165       self._compareGradient([50], axis, True, False)
    166 
    167   def testGradientExclusiveReverse(self):
    168     for axis in (-1, 0):
    169       self._compareGradient([50], axis, True, True)
    170 
    171   def testGradient2D(self):
    172     for axis in (-1, 0, 1):
    173       for exclusive in [True, False]:
    174         for reverse in [True, False]:
    175           self._compareGradient([5, 10], axis, exclusive, reverse)
    176 
    177 
    178 class CumprodTest(test.TestCase):
    179 
    180   valid_dtypes = [
    181       np.int32, np.int64, np.float16, np.float32, np.float64, np.complex64,
    182       np.complex128
    183   ]
    184 
    185   def _compare(self, x, axis, exclusive, reverse):
    186     np_out = handle_options(np.cumprod, x, axis, exclusive, reverse)
    187     with self.test_session(use_gpu=True):
    188       tf_out = math_ops.cumprod(x, axis, exclusive, reverse).eval()
    189 
    190     self.assertAllClose(np_out, tf_out)
    191 
    192   def _compareAll(self, x, axis):
    193     for exclusive in [True, False]:
    194       for reverse in [True, False]:
    195         self._compare(x, axis, exclusive, reverse)
    196 
    197   def testEmpty(self):
    198     for dtype in self.valid_dtypes:
    199       x = np.zeros([0]).astype(dtype)
    200       for axis in (-1, 0):
    201         self._compareAll(x, axis)
    202 
    203   def testAxisType(self):
    204     for dtype in self.valid_dtypes:
    205       x = np.arange(1, 6).reshape([5]).astype(dtype)
    206       for axis_dtype in [dtypes.int64, dtypes.int32]:
    207         with self.test_session(use_gpu=True):
    208           axis = constant_op.constant(0, axis_dtype)
    209           tf_out = math_ops.cumprod(x, axis).eval()
    210 
    211   def test1D(self):
    212     for dtype in self.valid_dtypes:
    213       x = np.arange(1, 6).reshape([5]).astype(dtype)
    214       for axis in (-1, 0):
    215         self._compareAll(x, axis)
    216 
    217   def test2D(self):
    218     for dtype in self.valid_dtypes:
    219       x = np.arange(1, 11).reshape([2, 5]).astype(dtype)
    220       for axis in (-2, -1, 0, 1):
    221         self._compareAll(x, axis)
    222 
    223   def test3D(self):
    224     for dtype in self.valid_dtypes:
    225       x = np.arange(1, 21).reshape([2, 2, 5]).astype(dtype)
    226       for axis in (-3, -2, -1, 0, 1, 2):
    227         self._compareAll(x, axis)
    228 
    229   def test6D(self):
    230     for dtype in self.valid_dtypes:
    231       x = np.arange(1, 145).reshape([2, 2, 3, 3, 2, 2]).astype(dtype)
    232       for axis in range(-6, 6, 3):
    233         self._compareAll(x, axis)
    234 
    235   def testInvalidAxis(self):
    236     x = np.arange(0, 10).reshape([2, 5]).astype(np.float32)
    237     input_tensor = ops.convert_to_tensor(x)
    238     with self.test_session(use_gpu=True):
    239       with self.assertRaisesWithPredicateMatch(
    240           errors_impl.InvalidArgumentError,
    241           lambda e: "Expected scan axis in the range [-2, 2)" in str(e)):
    242         math_ops.cumprod(input_tensor, -3).eval()
    243       with self.assertRaisesWithPredicateMatch(
    244           errors_impl.InvalidArgumentError,
    245           lambda e: "Expected scan axis in the range [-2, 2)" in str(e)):
    246         math_ops.cumprod(input_tensor, 2).eval()
    247       with self.assertRaisesWithPredicateMatch(
    248           errors_impl.InvalidArgumentError,
    249           lambda e: "axis must be a scalar" in str(e)):
    250         math_ops.cumprod(input_tensor, [0]).eval()
    251 
    252   def _compareGradient(self, shape, axis, exclusive, reverse):
    253     x = np.arange(1, 9).reshape(shape).astype(np.float64)
    254     with self.test_session(use_gpu=True):
    255       t = ops.convert_to_tensor(x)
    256       result = math_ops.cumprod(t, axis, exclusive, reverse)
    257       jacob_t, jacob_n = gradient_checker.compute_gradient(
    258           t, shape, result, shape, x_init_value=x, delta=1)
    259     self.assertAllClose(jacob_t, jacob_n, rtol=1e-8, atol=1e-8)
    260 
    261   def testGradient(self):
    262     for axis in (-1, 0):
    263       self._compareGradient([8], axis, False, False)
    264 
    265   def testGradientReverse(self):
    266     for axis in (-1, 0):
    267       self._compareGradient([8], axis, False, True)
    268 
    269   def testGradientExclusive(self):
    270     for axis in (-1, 0):
    271       self._compareGradient([8], axis, True, False)
    272 
    273   def testGradientExclusiveReverse(self):
    274     for axis in (-1, 0):
    275       self._compareGradient([8], axis, True, True)
    276 
    277   def testGradient2D(self):
    278     for axis in (-2, -1, 0, 1):
    279       for exclusive in [True, False]:
    280         for reverse in [True, False]:
    281           self._compareGradient([2, 4], axis, exclusive, reverse)
    282 
    283 
    284 if __name__ == "__main__":
    285   test.main()
    286