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