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 """Tests for SparseReshape."""
     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 dtypes
     24 from tensorflow.python.framework import sparse_tensor
     25 from tensorflow.python.ops import array_ops
     26 from tensorflow.python.ops import sparse_ops
     27 from tensorflow.python.platform import test
     28 
     29 
     30 class SparseReshapeTest(test.TestCase):
     31 
     32   def _SparseTensorPlaceholder(self):
     33     return sparse_tensor.SparseTensor(
     34         array_ops.placeholder(dtypes.int64),
     35         array_ops.placeholder(dtypes.float64),
     36         array_ops.placeholder(dtypes.int64))
     37 
     38   def _SparseTensorValue_5x6(self):
     39     ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2],
     40                     [3, 3]]).astype(np.int64)
     41     val = np.array([0, 10, 13, 14, 32, 33]).astype(np.float64)
     42 
     43     shape = np.array([5, 6]).astype(np.int64)
     44     return sparse_tensor.SparseTensorValue(ind, val, shape)
     45 
     46   def _SparseTensorValue_2x3x4(self):
     47     ind = np.array([[0, 0, 1], [0, 1, 0], [0, 1, 2], [1, 0, 3], [1, 1, 1],
     48                     [1, 1, 3], [1, 2, 2]])
     49     val = np.array([1, 10, 12, 103, 111, 113, 122])
     50     shape = np.array([2, 3, 4])
     51     return sparse_tensor.SparseTensorValue(ind, val, shape)
     52 
     53   def testStaticShapeInfoPreserved(self):
     54     sp_input = sparse_tensor.SparseTensor.from_value(
     55         self._SparseTensorValue_5x6())
     56     self.assertAllEqual((5, 6), sp_input.get_shape())
     57     sp_output = sparse_ops.sparse_reshape(sp_input, shape=(1, 5, 2, 3))
     58     self.assertAllEqual((1, 5, 2, 3), sp_output.get_shape())
     59 
     60   def testStaticShapeInfoPreservedWithInferredDims(self):
     61     sp_input = sparse_tensor.SparseTensor.from_value(
     62         self._SparseTensorValue_2x3x4())
     63     self.assertAllEqual((2, 3, 4), sp_input.get_shape())
     64     sp_output = sparse_ops.sparse_reshape(sp_input, shape=(2, -1))
     65     self.assertAllEqual((2, 3 * 4), sp_output.get_shape())
     66 
     67   def testRaisesIfMoreThanOneInferredDim(self):
     68     sp_input = sparse_tensor.SparseTensor.from_value(
     69         self._SparseTensorValue_2x3x4())
     70     with self.assertRaisesRegexp(ValueError, "At most one dimension can"):
     71       sparse_ops.sparse_reshape(sp_input, shape=(-1, 2, -1))
     72 
     73   def testRaisesIfInferredShapeNotPossible(self):
     74     sp_input = sparse_tensor.SparseTensor.from_value(
     75         self._SparseTensorValue_2x3x4())
     76     with self.assertRaisesRegexp(ValueError, "Cannot reshape"):
     77       sparse_ops.sparse_reshape(sp_input, shape=(-1, 7))
     78 
     79   def testSameShape(self):
     80     with self.test_session(use_gpu=False) as sess:
     81       input_val = self._SparseTensorValue_5x6()
     82       sp_output = sparse_ops.sparse_reshape(input_val, [5, 6])
     83 
     84       output_val = sess.run(sp_output)
     85       self.assertAllEqual(output_val.indices, input_val.indices)
     86       self.assertAllEqual(output_val.values, input_val.values)
     87       self.assertAllEqual(output_val.dense_shape, input_val.dense_shape)
     88 
     89   def testFeedSameShape(self):
     90     with self.test_session(use_gpu=False) as sess:
     91       sp_input = self._SparseTensorPlaceholder()
     92       input_val = self._SparseTensorValue_5x6()
     93       sp_output = sparse_ops.sparse_reshape(sp_input, [5, 6])
     94 
     95       output_val = sess.run(sp_output, {sp_input: input_val})
     96       self.assertAllEqual(output_val.indices, input_val.indices)
     97       self.assertAllEqual(output_val.values, input_val.values)
     98       self.assertAllEqual(output_val.dense_shape, input_val.dense_shape)
     99 
    100   def testWorksWellWithTfShape(self):
    101     with self.test_session(use_gpu=False) as sess:
    102       sp_input = self._SparseTensorPlaceholder()
    103       input_val = self._SparseTensorValue_5x6()
    104       shape = array_ops.shape(sp_input)  # tf.shape generates int32 output
    105       sp_output = sparse_ops.sparse_reshape(sp_input, shape)
    106 
    107       output_val = sess.run(sp_output, {sp_input: input_val})
    108       self.assertAllEqual(output_val.indices, input_val.indices)
    109       self.assertAllEqual(output_val.values, input_val.values)
    110       self.assertAllEqual(output_val.dense_shape, input_val.dense_shape)
    111 
    112   def testFeedSameShapeWithInferredDim(self):
    113     with self.test_session(use_gpu=False) as sess:
    114       sp_input = self._SparseTensorPlaceholder()
    115       input_val = self._SparseTensorValue_5x6()
    116       sp_output = sparse_ops.sparse_reshape(sp_input, [-1, 6])
    117 
    118       output_val = sess.run(sp_output, {sp_input: input_val})
    119       self.assertAllEqual(output_val.indices, input_val.indices)
    120       self.assertAllEqual(output_val.values, input_val.values)
    121       self.assertAllEqual(output_val.dense_shape, input_val.dense_shape)
    122 
    123   def testFeedNewShapeSameRank(self):
    124     with self.test_session(use_gpu=False) as sess:
    125       sp_input = self._SparseTensorPlaceholder()
    126       input_val = self._SparseTensorValue_5x6()
    127       sp_output = sparse_ops.sparse_reshape(sp_input, [3, 10])
    128 
    129       output_val = sess.run(sp_output, {sp_input: input_val})
    130       self.assertAllEqual(output_val.indices,
    131                           np.array([[0, 0], [0, 6], [0, 9], [1, 0], [2, 0],
    132                                     [2, 1]]))
    133       self.assertAllEqual(output_val.values, input_val.values)
    134       self.assertAllEqual(output_val.dense_shape, [3, 10])
    135 
    136   def testFeedNewShapeSameRankWithInferredDim(self):
    137     with self.test_session(use_gpu=False) as sess:
    138       sp_input = self._SparseTensorPlaceholder()
    139       input_val = self._SparseTensorValue_5x6()
    140       sp_output = sparse_ops.sparse_reshape(sp_input, [3, -1])
    141 
    142       output_val = sess.run(sp_output, {sp_input: input_val})
    143       self.assertAllEqual(output_val.indices,
    144                           np.array([[0, 0], [0, 6], [0, 9], [1, 0], [2, 0],
    145                                     [2, 1]]))
    146       self.assertAllEqual(output_val.values, input_val.values)
    147       self.assertAllEqual(output_val.dense_shape, [3, 10])
    148 
    149   def testUpRank(self):
    150     with self.test_session(use_gpu=False) as sess:
    151       input_val = self._SparseTensorValue_5x6()
    152       sp_output = sparse_ops.sparse_reshape(input_val, [2, 3, 5])
    153 
    154       output_val = sess.run(sp_output)
    155       self.assertAllEqual(output_val.indices,
    156                           np.array([[0, 0, 0], [0, 1, 1], [0, 1, 4], [0, 2, 0],
    157                                     [1, 1, 0], [1, 1, 1]]))
    158       self.assertAllEqual(output_val.values, input_val.values)
    159       self.assertAllEqual(output_val.dense_shape, [2, 3, 5])
    160 
    161   def testFeedUpRank(self):
    162     with self.test_session(use_gpu=False) as sess:
    163       sp_input = self._SparseTensorPlaceholder()
    164       input_val = self._SparseTensorValue_5x6()
    165       sp_output = sparse_ops.sparse_reshape(sp_input, [2, 3, 5])
    166 
    167       output_val = sess.run(sp_output, {sp_input: input_val})
    168       self.assertAllEqual(output_val.indices,
    169                           np.array([[0, 0, 0], [0, 1, 1], [0, 1, 4], [0, 2, 0],
    170                                     [1, 1, 0], [1, 1, 1]]))
    171       self.assertAllEqual(output_val.values, input_val.values)
    172       self.assertAllEqual(output_val.dense_shape, [2, 3, 5])
    173 
    174   def testFeedUpRankWithInferredDim(self):
    175     with self.test_session(use_gpu=False) as sess:
    176       sp_input = self._SparseTensorPlaceholder()
    177       input_val = self._SparseTensorValue_5x6()
    178       sp_output = sparse_ops.sparse_reshape(sp_input, [2, -1, 5])
    179 
    180       output_val = sess.run(sp_output, {sp_input: input_val})
    181       self.assertAllEqual(output_val.indices,
    182                           np.array([[0, 0, 0], [0, 1, 1], [0, 1, 4], [0, 2, 0],
    183                                     [1, 1, 0], [1, 1, 1]]))
    184       self.assertAllEqual(output_val.values, input_val.values)
    185       self.assertAllEqual(output_val.dense_shape, [2, 3, 5])
    186 
    187   def testFeedDownRank(self):
    188     with self.test_session(use_gpu=False) as sess:
    189       sp_input = self._SparseTensorPlaceholder()
    190       input_val = self._SparseTensorValue_2x3x4()
    191       sp_output = sparse_ops.sparse_reshape(sp_input, [6, 4])
    192 
    193       output_val = sess.run(sp_output, {sp_input: input_val})
    194       self.assertAllEqual(output_val.indices,
    195                           np.array([[0, 1], [1, 0], [1, 2], [3, 3], [4, 1],
    196                                     [4, 3], [5, 2]]))
    197       self.assertAllEqual(output_val.values, input_val.values)
    198       self.assertAllEqual(output_val.dense_shape, [6, 4])
    199 
    200   def testFeedDownRankWithInferredDim(self):
    201     with self.test_session(use_gpu=False) as sess:
    202       sp_input = self._SparseTensorPlaceholder()
    203       input_val = self._SparseTensorValue_2x3x4()
    204       sp_output = sparse_ops.sparse_reshape(sp_input, [6, -1])
    205 
    206       output_val = sess.run(sp_output, {sp_input: input_val})
    207       self.assertAllEqual(output_val.indices,
    208                           np.array([[0, 1], [1, 0], [1, 2], [3, 3], [4, 1],
    209                                     [4, 3], [5, 2]]))
    210       self.assertAllEqual(output_val.values, input_val.values)
    211       self.assertAllEqual(output_val.dense_shape, [6, 4])
    212 
    213   def testFeedMultipleInferredDims(self):
    214     with self.test_session(use_gpu=False) as sess:
    215       sp_input = self._SparseTensorPlaceholder()
    216       input_val = self._SparseTensorValue_5x6()
    217       sp_output = sparse_ops.sparse_reshape(sp_input, [4, -1, -1])
    218       with self.assertRaisesOpError("only one output dimension may be -1"):
    219         sess.run(sp_output, {sp_input: input_val})
    220 
    221   def testProvideStaticallyMismatchedSizes(self):
    222     input_val = self._SparseTensorValue_5x6()
    223     sp_input = sparse_tensor.SparseTensor.from_value(input_val)
    224     with self.assertRaisesRegexp(ValueError, "Cannot reshape"):
    225       sparse_ops.sparse_reshape(sp_input, [4, 7])
    226 
    227   def testFeedMismatchedSizes(self):
    228     with self.test_session(use_gpu=False) as sess:
    229       sp_input = self._SparseTensorPlaceholder()
    230       input_val = self._SparseTensorValue_5x6()
    231       sp_output = sparse_ops.sparse_reshape(sp_input, [4, 7])
    232       with self.assertRaisesOpError(
    233           "Input to reshape is a tensor with 30 dense values"):
    234         sess.run(sp_output, {sp_input: input_val})
    235 
    236   def testFeedMismatchedSizesWithInferredDim(self):
    237     with self.test_session(use_gpu=False) as sess:
    238       sp_input = self._SparseTensorPlaceholder()
    239       input_val = self._SparseTensorValue_5x6()
    240       sp_output = sparse_ops.sparse_reshape(sp_input, [4, -1])
    241       with self.assertRaisesOpError("requested shape requires a multiple"):
    242         sess.run(sp_output, {sp_input: input_val})
    243 
    244   def testFeedPartialShapes(self):
    245     with self.test_session(use_gpu=False):
    246       # Incorporate new rank into shape information if known
    247       sp_input = self._SparseTensorPlaceholder()
    248       sp_output = sparse_ops.sparse_reshape(sp_input, [2, 3, 5])
    249       self.assertListEqual(sp_output.indices.get_shape().as_list(), [None, 3])
    250       self.assertListEqual(sp_output.dense_shape.get_shape().as_list(), [3])
    251 
    252       # Incorporate known shape information about input indices in output
    253       # indices
    254       sp_input = self._SparseTensorPlaceholder()
    255       sp_input.indices.set_shape([5, None])
    256       sp_output = sparse_ops.sparse_reshape(sp_input, [2, 3, 5])
    257       self.assertListEqual(sp_output.indices.get_shape().as_list(), [5, 3])
    258       self.assertListEqual(sp_output.dense_shape.get_shape().as_list(), [3])
    259 
    260       # Even if new_shape has no shape information, we know the ranks of
    261       # output indices and shape
    262       sp_input = self._SparseTensorPlaceholder()
    263       sp_input.indices.set_shape([5, None])
    264       new_shape = array_ops.placeholder(dtypes.int64)
    265       sp_output = sparse_ops.sparse_reshape(sp_input, new_shape)
    266       self.assertListEqual(sp_output.indices.get_shape().as_list(), [5, None])
    267       self.assertListEqual(sp_output.dense_shape.get_shape().as_list(), [None])
    268 
    269   def testFeedDenseReshapeSemantics(self):
    270     with self.test_session(use_gpu=False) as sess:
    271       # Compute a random rank-5 initial shape and new shape, randomly sparsify
    272       # it, and check that the output of SparseReshape has the same semantics
    273       # as a dense reshape.
    274       factors = np.array([2] * 4 + [3] * 4 + [5] * 4)  # 810k total elements
    275       orig_rank = np.random.randint(2, 7)
    276       orig_map = np.random.randint(orig_rank, size=factors.shape)
    277       orig_shape = [np.prod(factors[orig_map == d]) for d in range(orig_rank)]
    278       new_rank = np.random.randint(2, 7)
    279       new_map = np.random.randint(new_rank, size=factors.shape)
    280       new_shape = [np.prod(factors[new_map == d]) for d in range(new_rank)]
    281 
    282       orig_dense = np.random.uniform(size=orig_shape)
    283       orig_indices = np.transpose(np.nonzero(orig_dense < 0.5))
    284       orig_values = orig_dense[orig_dense < 0.5]
    285 
    286       new_dense = np.reshape(orig_dense, new_shape)
    287       new_indices = np.transpose(np.nonzero(new_dense < 0.5))
    288       new_values = new_dense[new_dense < 0.5]
    289 
    290       sp_input = self._SparseTensorPlaceholder()
    291       input_val = sparse_tensor.SparseTensorValue(orig_indices, orig_values,
    292                                                   orig_shape)
    293       sp_output = sparse_ops.sparse_reshape(sp_input, new_shape)
    294 
    295       output_val = sess.run(sp_output, {sp_input: input_val})
    296       self.assertAllEqual(output_val.indices, new_indices)
    297       self.assertAllEqual(output_val.values, new_values)
    298       self.assertAllEqual(output_val.dense_shape, new_shape)
    299 
    300 
    301 if __name__ == "__main__":
    302   test.main()
    303