1 # Copyright 2015 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 Python ops defined in sparse_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 sparse_tensor 26 from tensorflow.python.framework import test_util 27 from tensorflow.python.ops import array_ops 28 from tensorflow.python.ops import gradient_checker 29 from tensorflow.python.ops import nn_ops 30 from tensorflow.python.ops import sparse_ops 31 from tensorflow.python.ops import variables 32 import tensorflow.python.ops.sparse_grad # pylint: disable=unused-import 33 from tensorflow.python.platform import googletest 34 from tensorflow.python.platform import test 35 36 37 # TODO(zongheng): it'd be great to factor out this function and various random 38 # SparseTensor gen funcs. 39 def _sparsify(x, thresh=0.5, index_dtype=np.int64): 40 x[x < thresh] = 0 41 42 non_zero = np.where(x) 43 x_indices = np.vstack(non_zero).astype(index_dtype).T 44 x_values = x[non_zero] 45 x_shape = x.shape 46 47 return sparse_tensor.SparseTensor( 48 indices=x_indices, values=x_values, dense_shape=x_shape), len(x_values) 49 50 51 class SparseToIndicatorTest(test_util.TensorFlowTestCase): 52 53 def _SparseTensor_5x6(self, dtype): 54 ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]) 55 val = np.array([0, 10, 13, 14, 32, 33]) 56 shape = np.array([5, 6]) 57 return sparse_tensor.SparseTensor( 58 constant_op.constant(ind, dtypes.int64), 59 constant_op.constant(val, dtype), 60 constant_op.constant(shape, dtypes.int64)) 61 62 def _SparseTensor_2x3x4(self, dtype): 63 # Includes two entries with the form [1, 1, x] : 150. 64 ind = np.array([[0, 0, 1], [0, 1, 0], [0, 1, 2], [1, 0, 3], [1, 1, 0], 65 [1, 1, 1], [1, 1, 2], [1, 2, 2]]) 66 val = np.array([1, 10, 12, 103, 150, 149, 150, 122]) 67 shape = np.array([2, 3, 4]) 68 return sparse_tensor.SparseTensor( 69 constant_op.constant(ind, dtypes.int64), 70 constant_op.constant(val, dtype), 71 constant_op.constant(shape, dtypes.int64)) 72 73 def testInt32(self): 74 with self.test_session(use_gpu=False): 75 sp_input = self._SparseTensor_5x6(dtypes.int32) 76 output = sparse_ops.sparse_to_indicator(sp_input, 50).eval() 77 78 expected_output = np.zeros((5, 50), dtype=np.bool) 79 expected_trues = ((0, 0), (1, 10), (1, 13), (1, 14), (3, 32), (3, 33)) 80 for expected_true in expected_trues: 81 expected_output[expected_true] = True 82 83 self.assertAllEqual(output, expected_output) 84 85 def testInt64(self): 86 with self.test_session(use_gpu=False): 87 sp_input = self._SparseTensor_5x6(dtypes.int64) 88 output = sparse_ops.sparse_to_indicator(sp_input, 50).eval() 89 90 expected_output = np.zeros((5, 50), dtype=np.bool) 91 expected_trues = [(0, 0), (1, 10), (1, 13), (1, 14), (3, 32), (3, 33)] 92 for expected_true in expected_trues: 93 expected_output[expected_true] = True 94 95 self.assertAllEqual(output, expected_output) 96 97 def testHigherRank(self): 98 with self.test_session(use_gpu=False): 99 sp_input = self._SparseTensor_2x3x4(dtypes.int64) 100 output = sparse_ops.sparse_to_indicator(sp_input, 200).eval() 101 102 expected_output = np.zeros((2, 3, 200), dtype=np.bool) 103 expected_trues = [(0, 0, 1), (0, 1, 10), (0, 1, 12), (1, 0, 103), 104 (1, 1, 149), (1, 1, 150), (1, 2, 122)] 105 for expected_true in expected_trues: 106 expected_output[expected_true] = True 107 108 self.assertAllEqual(output, expected_output) 109 110 111 class SparseMergeTest(test_util.TensorFlowTestCase): 112 113 def _SparseTensorValue_3x50(self, indices_dtype, values_dtype): 114 # NOTE: This input is intentionally not sorted to validate the 115 # already_sorted flag below. 116 ind = np.array([[0, 0], [1, 0], [1, 2], [2, 0], [2, 1], [1, 1]]) 117 # NB: these are not sorted 118 indices = np.array([0, 13, 10, 33, 32, 14]) 119 values = np.array([-3, 4, 1, 9, 5, 1]) 120 shape = np.array([3, 3]) 121 indices = sparse_tensor.SparseTensorValue( 122 np.array(ind, np.int64), 123 np.array(indices, indices_dtype), np.array(shape, np.int64)) 124 values = sparse_tensor.SparseTensorValue( 125 np.array(ind, np.int64), 126 np.array(values, values_dtype), np.array(shape, np.int64)) 127 return indices, values 128 129 def _SparseTensor_3x50(self, indices_dtype, values_dtype): 130 indices, values = self._SparseTensorValue_3x50(indices_dtype, values_dtype) 131 return (sparse_tensor.SparseTensor.from_value(indices), 132 sparse_tensor.SparseTensor.from_value(values)) 133 134 def _AssertResultsSorted(self, output, vocab_size): 135 self.assertAllEqual(output.indices, 136 [[0, 0], [1, 10], [1, 13], [1, 14], [2, 32], [2, 33]]) 137 self.assertAllEqual(output.values, [-3, 1, 4, 1, 5, 9]) 138 self.assertAllEqual(output.dense_shape, [3, vocab_size]) 139 140 def _AssertResultsNotSorted(self, output, vocab_size): 141 self.assertAllEqual(output.indices, 142 [[0, 0], [1, 13], [1, 10], [2, 33], [2, 32], [1, 14]]) 143 self.assertAllEqual(output.values, [-3, 4, 1, 9, 5, 1]) 144 self.assertAllEqual(output.dense_shape, [3, vocab_size]) 145 146 def testInt32AndFloat32(self): 147 vocab_size = 50 148 indices_v, values_v = self._SparseTensorValue_3x50(np.int32, np.float32) 149 with self.test_session(use_gpu=False) as sess: 150 for indices in (indices_v, 151 sparse_tensor.SparseTensor.from_value(indices_v)): 152 for values in (values_v, 153 sparse_tensor.SparseTensor.from_value(values_v)): 154 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 155 156 output = sess.run(sp_output) 157 self._AssertResultsSorted(output, vocab_size) 158 159 def testInt64AndFloat32(self): 160 vocab_size = 50 161 with self.test_session(use_gpu=False) as sess: 162 indices, values = self._SparseTensor_3x50(np.int64, np.float32) 163 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 164 165 output = sess.run(sp_output) 166 self._AssertResultsSorted(output, vocab_size) 167 168 def testInt64AndFloat64(self): 169 vocab_size = 50 170 with self.test_session(use_gpu=False) as sess: 171 indices, values = self._SparseTensor_3x50(np.int64, np.float64) 172 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 173 174 output = sess.run(sp_output) 175 self._AssertResultsSorted(output, vocab_size) 176 177 def testInt32AndFloat32NonCanonicalOrder(self): 178 vocab_size = 50 179 with self.test_session(use_gpu=False) as sess: 180 indices, values = self._SparseTensor_3x50(np.int32, np.float32) 181 sp_output = sparse_ops.sparse_merge( 182 indices, values, vocab_size, already_sorted=True) 183 184 output = sess.run(sp_output) 185 self._AssertResultsNotSorted(output, vocab_size) 186 187 def testInt64AndFloat32NonCanonicalOrder(self): 188 vocab_size = 50 189 with self.test_session(use_gpu=False) as sess: 190 indices, values = self._SparseTensor_3x50(np.int64, np.float32) 191 sp_output = sparse_ops.sparse_merge( 192 indices, values, vocab_size, already_sorted=True) 193 194 output = sess.run(sp_output) 195 self._AssertResultsNotSorted(output, vocab_size) 196 197 def testInt64AndFloat64NonCanonicalOrder(self): 198 vocab_size = 50 199 vocab_size_tensor = constant_op.constant(vocab_size, dtypes.int64) 200 with self.test_session(use_gpu=False) as sess: 201 indices, values = self._SparseTensor_3x50(np.int64, np.float64) 202 sp_output = sparse_ops.sparse_merge( 203 indices, values, vocab_size_tensor, already_sorted=True) 204 205 output = sess.run(sp_output) 206 self._AssertResultsNotSorted(output, vocab_size) 207 208 209 class SparseMergeHighDimTest(test_util.TensorFlowTestCase): 210 211 def _SparseTensor_3x50(self, indices_dtype, values_dtype): 212 # NOTE: This input is intentionally not sorted to validate the 213 # already_sorted flag below. 214 ind = np.array([[0, 0], [1, 0], [1, 2], [2, 0], [2, 1], [1, 1]]) 215 # NB: these are not sorted 216 indices0 = np.array([0, 13, 10, 33, 32, 14]) 217 indices1 = np.array([12, 4, 0, 0, 1, 30]) 218 values = np.array([-3, 4, 1, 9, 5, 1]) 219 shape = np.array([3, 3]) 220 indices0 = sparse_tensor.SparseTensorValue( 221 np.array(ind, np.int64), 222 np.array(indices0, indices_dtype), np.array(shape, np.int64)) 223 indices1 = sparse_tensor.SparseTensorValue( 224 np.array(ind, np.int64), 225 np.array(indices1, indices_dtype), np.array(shape, np.int64)) 226 values = sparse_tensor.SparseTensorValue( 227 np.array(ind, np.int64), 228 np.array(values, values_dtype), np.array(shape, np.int64)) 229 return ([sparse_tensor.SparseTensor.from_value(indices0), 230 sparse_tensor.SparseTensor.from_value(indices1)], 231 sparse_tensor.SparseTensor.from_value(values)) 232 233 def _AssertResultsSorted(self, output, vocab_size): 234 self.assertAllEqual( 235 output.indices, 236 [[0, 0, 12], [1, 10, 0], [1, 13, 4], [1, 14, 30], [2, 32, 1], 237 [2, 33, 0]]) 238 self.assertAllEqual(output.values, [-3, 1, 4, 1, 5, 9]) 239 self.assertAllEqual(output.dense_shape, [3] + vocab_size) 240 241 def testInt64AndFloat32(self): 242 vocab_size = [50, 31] 243 with self.test_session(use_gpu=False) as sess: 244 indices, values = self._SparseTensor_3x50(np.int64, np.float32) 245 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 246 247 output = sess.run(sp_output) 248 self._AssertResultsSorted(output, vocab_size) 249 250 def testInt64AndFloat64(self): 251 vocab_size = [50, 31] 252 with self.test_session(use_gpu=False) as sess: 253 indices, values = self._SparseTensor_3x50(np.int64, np.float64) 254 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 255 256 output = sess.run(sp_output) 257 self._AssertResultsSorted(output, vocab_size) 258 259 def testInt64AndFloat64Shape(self): 260 vocab_size = [50, 30] 261 with self.test_session(use_gpu=False) as sess: 262 indices, values = self._SparseTensor_3x50(np.int64, np.float64) 263 sp_output = sparse_ops.sparse_merge(indices, values, vocab_size) 264 265 output = sess.run(sp_output) 266 self._AssertResultsSorted(output, vocab_size) 267 268 269 class SparseRetainTest(test_util.TensorFlowTestCase): 270 271 def _SparseTensorValue_5x6(self): 272 ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]) 273 val = np.array([0, 10, 13, 14, 32, 33]) 274 shape = np.array([5, 6]) 275 return sparse_tensor.SparseTensorValue( 276 np.array(ind, np.int64), 277 np.array(val, np.int32), np.array(shape, np.int64)) 278 279 def _SparseTensor_5x6(self): 280 return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_5x6()) 281 282 def testBasic(self): 283 with self.test_session(use_gpu=False) as sess: 284 for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()): 285 to_retain = np.array([1, 0, 0, 1, 1, 0], dtype=np.bool) 286 sp_output = sparse_ops.sparse_retain(sp_input, to_retain) 287 288 output = sess.run(sp_output) 289 290 self.assertAllEqual(output.indices, [[0, 0], [1, 4], [3, 2]]) 291 self.assertAllEqual(output.values, [0, 14, 32]) 292 self.assertAllEqual(output.dense_shape, [5, 6]) 293 294 def testRetainNone(self): 295 with self.test_session(use_gpu=False) as sess: 296 sp_input = self._SparseTensor_5x6() 297 to_retain = np.zeros((6,), dtype=np.bool) 298 sp_output = sparse_ops.sparse_retain(sp_input, to_retain) 299 300 output = sess.run(sp_output) 301 302 self.assertAllEqual(output.indices, np.array([]).reshape((0, 2))) 303 self.assertAllEqual(output.values, []) 304 self.assertAllEqual(output.dense_shape, [5, 6]) 305 306 def testMismatchedRetainShape(self): 307 with self.test_session(use_gpu=False): 308 sp_input = self._SparseTensor_5x6() 309 to_retain = np.array([1, 0, 0, 1, 0], dtype=np.bool) 310 with self.assertRaises(ValueError): 311 sparse_ops.sparse_retain(sp_input, to_retain) 312 313 314 class SparseResetShapeTest(test_util.TensorFlowTestCase): 315 316 _IND_2_5_6 = np.array( 317 [[0, 0, 0], [0, 1, 0], [0, 1, 3], [1, 1, 4], [1, 3, 2], [1, 3, 3]], 318 dtype=np.int64) 319 _VAL_2_5_6 = np.array([0, 10, 13, 14, 32, 33], dtype=np.int32) 320 _SHP_2_5_6 = np.array([2, 5, 6], dtype=np.int64) 321 322 def _SparseTensor_2x5x6(self): 323 return sparse_tensor.SparseTensor( 324 constant_op.constant(self._IND_2_5_6, dtypes.int64), 325 constant_op.constant(self._VAL_2_5_6, dtypes.int32), 326 constant_op.constant(self._SHP_2_5_6, dtypes.int64)) 327 328 def _SparseTensor_2x5x6_Empty(self): 329 return sparse_tensor.SparseTensor( 330 constant_op.constant( 331 np.empty(shape=[0, 3], dtype=np.int64), dtypes.int64), 332 constant_op.constant(np.empty(shape=[0], dtype=np.int32), dtypes.int32), 333 constant_op.constant(self._SHP_2_5_6, dtypes.int64)) 334 335 def _SparseTensorValue_2x5x6(self): 336 return sparse_tensor.SparseTensorValue(self._IND_2_5_6, self._VAL_2_5_6, 337 self._SHP_2_5_6) 338 339 def testStaticShapeInfoPreservedWhenNewShapeIsProvidedAndStatic(self): 340 sp_input = self._SparseTensor_2x5x6() 341 new_shape = np.array([3, 6, 7], dtype=np.int64) 342 sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) 343 self.assertAllEqual([3, 6, 7], sp_output.get_shape()) 344 345 def testBasic(self): 346 with self.test_session(use_gpu=False) as sess: 347 sp_input = self._SparseTensor_2x5x6() 348 new_shape = np.array([3, 6, 7], dtype=np.int64) 349 sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) 350 351 output = sess.run(sp_output) 352 353 self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], 354 [1, 1, 4], [1, 3, 2], [1, 3, 3]]) 355 self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) 356 self.assertAllEqual(output.dense_shape, [3, 6, 7]) 357 358 def testInputUnavailableInGraphConstructionOk(self): 359 with self.test_session(use_gpu=False) as sess: 360 sp_input = self._SparseTensorValue_2x5x6() 361 new_shape = np.array([3, 6, 7], dtype=np.int64) 362 sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) 363 364 output = sess.run(sp_output) 365 366 self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], 367 [1, 1, 4], [1, 3, 2], [1, 3, 3]]) 368 self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) 369 self.assertAllEqual(output.dense_shape, [3, 6, 7]) 370 371 def testFeedInputUnavailableInGraphConstructionOk(self): 372 with self.test_session(use_gpu=False) as sess: 373 sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32) 374 new_shape = np.array([3, 6, 7], dtype=np.int64) 375 sp_output = sparse_ops.sparse_reset_shape(sp_input, new_shape) 376 377 output = sess.run(sp_output, 378 feed_dict={sp_input: self._SparseTensorValue_2x5x6()}) 379 380 self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], 381 [1, 1, 4], [1, 3, 2], [1, 3, 3]]) 382 self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) 383 self.assertAllEqual(output.dense_shape, [3, 6, 7]) 384 385 def testTightBoundingBox(self): 386 with self.test_session(use_gpu=False) as sess: 387 sp_input = self._SparseTensor_2x5x6() 388 sp_output = sparse_ops.sparse_reset_shape(sp_input) 389 390 output = sess.run(sp_output) 391 392 self.assertAllEqual(output.indices, [[0, 0, 0], [0, 1, 0], [0, 1, 3], 393 [1, 1, 4], [1, 3, 2], [1, 3, 3]]) 394 self.assertAllEqual(output.values, [0, 10, 13, 14, 32, 33]) 395 self.assertAllEqual(output.dense_shape, [2, 4, 5]) 396 397 def testTightBoundingBoxEmpty(self): 398 with self.test_session(use_gpu=False) as sess: 399 sp_input = self._SparseTensor_2x5x6_Empty() 400 sp_output = sparse_ops.sparse_reset_shape(sp_input) 401 402 output = sess.run(sp_output) 403 404 self.assertAllEqual(output.indices.shape, [0, 3]) 405 self.assertAllEqual(output.values.shape, [0]) 406 self.assertAllEqual(output.dense_shape, [0, 0, 0]) 407 408 def testInvalidRank(self): 409 with self.test_session(use_gpu=False): 410 sp_input = self._SparseTensor_2x5x6() 411 new_shape = np.array([3, 7], dtype=np.int64) 412 413 with self.assertRaises(ValueError): 414 sparse_ops.sparse_reset_shape(sp_input, new_shape) 415 416 def testInvalidRankNewShapeUnavailableInGraphConstruction(self): 417 with self.test_session(use_gpu=False) as sess: 418 new_shape = array_ops.placeholder(dtype=dtypes.int64) 419 sp_input = self._SparseTensor_2x5x6() 420 out = sparse_ops.sparse_reset_shape(sp_input, new_shape) 421 422 with self.assertRaisesOpError("x == y did not hold element-wise"): 423 sess.run(out, feed_dict={new_shape: np.array([3, 7], dtype=np.int64)}) 424 425 def testInvalidDimensionSizeStatic(self): 426 sp_input = self._SparseTensor_2x5x6() 427 new_shape = np.array([3, 7, 5], dtype=np.int64) 428 429 with self.assertRaisesRegexp(ValueError, "should have dimension sizes"): 430 sparse_ops.sparse_reset_shape(sp_input, new_shape) 431 432 def testInvalidDimensionSizeDynamic(self): 433 with self.test_session(use_gpu=False) as sess: 434 sp_input = self._SparseTensor_2x5x6() 435 new_shape = array_ops.placeholder(dtype=dtypes.int32) 436 out = sparse_ops.sparse_reset_shape(sp_input, new_shape) 437 438 with self.assertRaisesOpError("x <= y did not hold element-wise"): 439 sess.run(out, feed_dict={new_shape: [3, 7, 5]}) 440 441 def testInvalidDimensionSizeInputUnavailableInGraphConstruction(self): 442 sp_input = array_ops.sparse_placeholder(dtype=dtypes.int32) 443 with self.test_session(use_gpu=False) as sess: 444 new_shape = np.array([3, 7, 5], dtype=np.int64) 445 out = sparse_ops.sparse_reset_shape(sp_input, new_shape) 446 447 with self.assertRaisesOpError("x <= y did not hold element-wise"): 448 sess.run(out, feed_dict={sp_input: self._SparseTensorValue_2x5x6()}) 449 450 451 class SparseFillEmptyRowsTest(test_util.TensorFlowTestCase): 452 453 def _SparseTensorValue_5x6(self, dtype=np.int32): 454 ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]) 455 val = np.array([0, 10, 13, 14, 32, 33]) 456 shape = np.array([5, 6]) 457 return sparse_tensor.SparseTensorValue( 458 np.array(ind, np.int64), np.array(val, dtype), np.array( 459 shape, np.int64)) 460 461 def _SparseTensor_5x6(self): 462 return sparse_tensor.SparseTensor.from_value(self._SparseTensorValue_5x6()) 463 464 def _SparseTensor_String5x6(self): 465 ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]) 466 val = np.array(["a", "b", "c", "d", "e", "f"]) 467 shape = np.array([5, 6]) 468 return sparse_tensor.SparseTensor( 469 constant_op.constant(ind, dtypes.int64), 470 constant_op.constant(val, dtypes.string), 471 constant_op.constant(shape, dtypes.int64)) 472 473 def _SparseTensor_2x6(self): 474 ind = np.array([[0, 0], [1, 0], [1, 3], [1, 4]]) 475 val = np.array([0, 10, 13, 14]) 476 shape = np.array([2, 6]) 477 return sparse_tensor.SparseTensor( 478 constant_op.constant(ind, dtypes.int64), 479 constant_op.constant(val, dtypes.int32), 480 constant_op.constant(shape, dtypes.int64)) 481 482 def testFillNumber(self): 483 with self.test_session(use_gpu=False) as sess: 484 for sp_input in (self._SparseTensorValue_5x6(), self._SparseTensor_5x6()): 485 sp_output, empty_row_indicator = ( 486 sparse_ops.sparse_fill_empty_rows(sp_input, -1)) 487 488 output, empty_row_indicator_out = sess.run( 489 [sp_output, empty_row_indicator]) 490 491 self.assertAllEqual( 492 output.indices, 493 [[0, 0], [1, 0], [1, 3], [1, 4], [2, 0], [3, 2], [3, 3], [4, 0]]) 494 self.assertAllEqual(output.values, [0, 10, 13, 14, -1, 32, 33, -1]) 495 self.assertAllEqual(output.dense_shape, [5, 6]) 496 self.assertAllEqual(empty_row_indicator_out, 497 np.array([0, 0, 1, 0, 1]).astype(np.bool)) 498 499 def testFillFloat(self): 500 with self.test_session(use_gpu=False) as sess: 501 values = constant_op.constant( 502 [0.0, 10.0, 13.0, 14.0, 32.0, 33.0], dtype=dtypes.float64) 503 default_value = constant_op.constant(-1.0, dtype=dtypes.float64) 504 sp_input = sparse_tensor.SparseTensorValue( 505 indices=np.array([[0, 0], [1, 0], [1, 3], [1, 4], [3, 2], [3, 3]]), 506 values=values, 507 dense_shape=np.array([5, 6])) 508 sp_output, empty_row_indicator = (sparse_ops.sparse_fill_empty_rows( 509 sp_input, default_value)) 510 output, empty_row_indicator_out = sess.run( 511 [sp_output, empty_row_indicator]) 512 513 self.assertAllEqual(output.indices, [[0, 0], [1, 0], [1, 3], [1, 4], 514 [2, 0], [3, 2], [3, 3], [4, 0]]) 515 self.assertAllClose(output.values, [0, 10, 13, 14, -1, 32, 33, -1]) 516 self.assertAllEqual(output.dense_shape, [5, 6]) 517 self.assertAllEqual(empty_row_indicator_out, 518 np.array([0, 0, 1, 0, 1]).astype(np.bool)) 519 520 values_grad_err = gradient_checker.compute_gradient_error( 521 values, values.shape.as_list(), sp_output.values, [8], delta=1e-8) 522 self.assertGreater(values_grad_err, 0) 523 self.assertLess(values_grad_err, 1e-8) 524 525 default_value_grad_err = gradient_checker.compute_gradient_error( 526 default_value, 527 default_value.shape.as_list(), 528 sp_output.values, [8], 529 delta=1e-8) 530 self.assertGreater(default_value_grad_err, 0) 531 self.assertLess(default_value_grad_err, 1e-8) 532 533 def testFillString(self): 534 with self.test_session(use_gpu=False) as sess: 535 sp_input = self._SparseTensor_String5x6() 536 sp_output, empty_row_indicator = ( 537 sparse_ops.sparse_fill_empty_rows(sp_input, "")) 538 539 output, empty_row_indicator_out = sess.run( 540 [sp_output, empty_row_indicator]) 541 542 self.assertAllEqual( 543 output.indices, 544 [[0, 0], [1, 0], [1, 3], [1, 4], [2, 0], [3, 2], [3, 3], [4, 0]]) 545 self.assertAllEqual(output.values, 546 [b"a", b"b", b"c", b"d", b"", b"e", b"f", b""]) 547 self.assertAllEqual(output.dense_shape, [5, 6]) 548 self.assertAllEqual(empty_row_indicator_out, 549 np.array([0, 0, 1, 0, 1]).astype(np.bool)) 550 551 def testNoEmptyRows(self): 552 with self.test_session(use_gpu=False) as sess: 553 sp_input = self._SparseTensor_2x6() 554 sp_output, empty_row_indicator = ( 555 sparse_ops.sparse_fill_empty_rows(sp_input, -1)) 556 557 output, empty_row_indicator_out = sess.run( 558 [sp_output, empty_row_indicator]) 559 560 self.assertAllEqual(output.indices, [[0, 0], [1, 0], [1, 3], [1, 4]]) 561 self.assertAllEqual(output.values, [0, 10, 13, 14]) 562 self.assertAllEqual(output.dense_shape, [2, 6]) 563 self.assertAllEqual(empty_row_indicator_out, np.zeros(2).astype(np.bool)) 564 565 566 class SparseAddTest(test_util.TensorFlowTestCase): 567 568 def testValuesInVariable(self): 569 indices = constant_op.constant([[1]], dtype=dtypes.int64) 570 values = variables.Variable([1], trainable=False, dtype=dtypes.float32) 571 shape = constant_op.constant([1], dtype=dtypes.int64) 572 573 sp_input = sparse_tensor.SparseTensor(indices, values, shape) 574 sp_output = sparse_ops.sparse_add(sp_input, sp_input) 575 576 with self.test_session(use_gpu=False) as sess: 577 sess.run(variables.global_variables_initializer()) 578 output = sess.run(sp_output) 579 self.assertAllEqual(output.values, [2]) 580 581 582 class SparseReduceTest(test_util.TensorFlowTestCase): 583 584 # [[1, ?, 2] 585 # [?, 3, ?]] 586 # where ? is implicitly-zero. 587 ind = np.array([[0, 0], [0, 2], [1, 1]]).astype(np.int64) 588 vals = np.array([1, 1, 1]).astype(np.int32) 589 dense_shape = np.array([2, 3]).astype(np.int64) 590 591 def _compare(self, sp_t, reduction_axes, ndims, keep_dims, do_sum): 592 densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval() 593 594 np_ans = densified 595 if reduction_axes is None: 596 if do_sum: 597 np_ans = np.sum(np_ans, keepdims=keep_dims) 598 else: 599 np_ans = np.max(np_ans, keepdims=keep_dims) 600 else: 601 if not isinstance(reduction_axes, list): # Single scalar. 602 reduction_axes = [reduction_axes] 603 reduction_axes = np.array(reduction_axes).astype(np.int32) 604 # Handles negative axes. 605 reduction_axes = (reduction_axes + ndims) % ndims 606 # Loop below depends on sorted. 607 reduction_axes.sort() 608 for ra in reduction_axes.ravel()[::-1]: 609 if do_sum: 610 np_ans = np.sum(np_ans, axis=ra, keepdims=keep_dims) 611 else: 612 np_ans = np.max(np_ans, axis=ra, keepdims=keep_dims) 613 614 with self.test_session(): 615 if do_sum: 616 tf_dense_ans = sparse_ops.sparse_reduce_sum(sp_t, reduction_axes, 617 keep_dims) 618 else: 619 tf_dense_ans = sparse_ops.sparse_reduce_max(sp_t, reduction_axes, 620 keep_dims) 621 out_dense = tf_dense_ans.eval() 622 623 if do_sum: 624 tf_sparse_ans = sparse_ops.sparse_reduce_sum_sparse(sp_t, 625 reduction_axes, 626 keep_dims) 627 else: 628 tf_sparse_ans = sparse_ops.sparse_reduce_max_sparse(sp_t, 629 reduction_axes, 630 keep_dims) 631 # Convert to dense for comparison purposes. 632 out_sparse = sparse_ops.sparse_tensor_to_dense(tf_sparse_ans).eval() 633 634 self.assertAllClose(np_ans, out_dense) 635 self.assertAllClose(np_ans, out_sparse) 636 637 def _compare_all(self, sp_t, reduction_axes, ndims): 638 self._compare(sp_t, reduction_axes, ndims, False, False) 639 self._compare(sp_t, reduction_axes, ndims, False, True) 640 self._compare(sp_t, reduction_axes, ndims, True, False) 641 self._compare(sp_t, reduction_axes, ndims, True, True) 642 643 def testSimpleAndRandomInputs(self): 644 if np.__version__ == "1.13.0": 645 self.skipTest("numpy 1.13.0 bug") 646 647 sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape) 648 649 with self.test_session(use_gpu=False): 650 self._compare_all(sp_t, None, ndims=2) 651 self._compare_all(sp_t, 0, ndims=2) 652 self._compare_all(sp_t, [1], ndims=2) 653 self._compare_all(sp_t, [0, 1], ndims=2) 654 self._compare_all(sp_t, [1, 0], ndims=2) 655 self._compare_all(sp_t, [-1], ndims=2) 656 self._compare_all(sp_t, [1, -2], ndims=2) 657 658 np.random.seed(1618) 659 test_dims = [(1618, 1, 11, 7, 1), (1,), (1, 1, 1)] 660 with self.test_session(use_gpu=False): 661 for dims in test_dims: 662 sp_t, unused_nnz = _sparsify(np.random.randn(*dims)) 663 # reduce all using None 664 self._compare_all(sp_t, None, ndims=len(dims)) 665 # reduce random axes from 1D to N-D 666 for d in range(1, len(dims) + 1): 667 axes = np.random.choice(len(dims), size=d, replace=False).tolist() 668 self._compare_all(sp_t, axes, ndims=len(dims)) 669 670 def testInvalidAxes(self): 671 sp_t = sparse_tensor.SparseTensor(self.ind, self.vals, self.dense_shape) 672 with self.test_session(use_gpu=False): 673 with self.assertRaisesOpError("Invalid reduction dimension -3"): 674 sparse_ops.sparse_reduce_sum(sp_t, -3).eval() 675 with self.assertRaisesOpError("Invalid reduction dimension 2"): 676 sparse_ops.sparse_reduce_sum(sp_t, 2).eval() 677 with self.assertRaisesOpError("Invalid reduction dimension -3"): 678 sparse_ops.sparse_reduce_max(sp_t, -3).eval() 679 with self.assertRaisesOpError("Invalid reduction dimension 2"): 680 sparse_ops.sparse_reduce_max(sp_t, 2).eval() 681 682 def testGradient(self): 683 if np.__version__ == "1.13.0": 684 self.skipTest("numpy 1.13.0 bug") 685 686 np.random.seed(8161) 687 test_dims = [(11, 1, 5, 7, 1), (2, 2)] 688 with self.test_session(use_gpu=False): 689 for dims in test_dims: 690 sp_t, nnz = _sparsify(np.random.randn(*dims)) 691 # reduce random axes from 1D to N-D 692 for d in range(1, len(dims) + 1): 693 axes = np.random.choice(len(dims), size=d, replace=False).tolist() 694 reduced = sparse_ops.sparse_reduce_sum(sp_t, axes) 695 696 err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,), 697 reduced, 698 reduced.eval().shape) 699 self.assertLess(err, 1e-3) 700 701 # Tests for negative axes. 702 reduced = sparse_ops.sparse_reduce_sum(sp_t, -1) 703 err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,), 704 reduced, 705 reduced.eval().shape) 706 self.assertLess(err, 1e-3) 707 708 709 class SparseMathOpsTest(test_util.TensorFlowTestCase): 710 711 def _check(self, result_tensor, result_np, input_sp_t): 712 self.assertTrue(isinstance(result_tensor, sparse_tensor.SparseTensor)) 713 self.assertTrue(isinstance(input_sp_t, sparse_tensor.SparseTensor)) 714 self.assertAllEqual(input_sp_t.indices.eval(), result_tensor.indices.eval()) 715 self.assertAllEqual(input_sp_t.dense_shape.eval(), 716 result_tensor.dense_shape.eval()) 717 718 res_densified = sparse_ops.sparse_to_dense(result_tensor.indices, 719 result_tensor.dense_shape, 720 result_tensor.values).eval() 721 self.assertAllEqual(result_np, res_densified) 722 723 def testCwiseDivAndMul(self): 724 np.random.seed(1618) 725 sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)] 726 dense_shapes = [(10, 10, 1), (5, 5), (1,), (1, 7)] 727 728 with self.test_session(use_gpu=False): 729 for dtype in [np.float32, np.float64, np.int32, np.int64]: 730 for sp_shape, dense_shape in zip(sp_shapes, dense_shapes): 731 sp_vals_np = np.random.rand(*sp_shape).astype(dtype) + 1 732 dense_vals_np = np.random.rand(*dense_shape).astype(dtype) + 1 733 sp_t, unused_nnz = _sparsify(sp_vals_np, thresh=1.5) 734 sp_t_densified = sparse_ops.sparse_tensor_to_dense(sp_t).eval() 735 dense_t = constant_op.constant(dense_vals_np) 736 737 self._check(sp_t / dense_t, sp_t_densified / dense_vals_np, sp_t) 738 # Check commutative. 739 self._check(sp_t * dense_t, sp_t_densified * dense_vals_np, sp_t) 740 self._check(dense_t * sp_t, sp_t_densified * dense_vals_np, sp_t) 741 742 if dtype in [np.int32, np.int64]: 743 res = sp_t / dense_t # should invoke "__truediv__" 744 self.assertEqual(res.values.eval().dtype, np.float64) 745 746 def testCwiseAdd(self): 747 with self.test_session(use_gpu=False): 748 # Identity(2) + AllOnes(2,2). Should be equal to 2 * Identity(2). 749 indices = [[0, 0], [1, 1]] 750 vals = [1, 1] 751 shape = (2, 2) 752 753 sp_t = sparse_tensor.SparseTensor(indices, vals, shape) 754 dense_t = array_ops.ones(shape, dtype=dtypes.int32) 755 self._check( 756 sparse_ops.sparse_dense_cwise_add(sp_t, dense_t), 757 np.identity(2) * 2, sp_t) 758 759 # Variant of above, but broadcasts the dense side. 760 dense_t = array_ops.ones([1], dtype=dtypes.int32) 761 self._check( 762 sparse_ops.sparse_dense_cwise_add(sp_t, dense_t), 763 np.identity(2) * 2, sp_t) 764 765 def testGradients(self): 766 np.random.seed(1618) 767 sp_shapes = [(10, 10, 10), (5, 5), (1618,), (3, 3, 7)] 768 dense_shapes = [(10, 10, 1), (5, 5), (1,), (1, 7)] 769 770 with self.test_session(use_gpu=False): 771 for dtype in [np.float32, np.float64]: 772 for sp_shape, dense_shape in zip(sp_shapes, dense_shapes): 773 sp_vals_np = np.random.rand(*sp_shape).astype(dtype) + 1 774 dense_vals_np = np.random.rand(*dense_shape).astype(dtype) + 1 775 sp_t, nnz = _sparsify(sp_vals_np, thresh=1.5) 776 dense_t = constant_op.constant(dense_vals_np) 777 778 cmul = sp_t * dense_t 779 err = gradient_checker.compute_gradient_error([sp_t.values, dense_t], 780 [(nnz,), dense_shape], 781 cmul.values, (nnz,)) 782 self.assertLess(err, 1e-4) 783 784 cdiv = sp_t / dense_t 785 err = gradient_checker.compute_gradient_error(sp_t.values, (nnz,), 786 cdiv.values, (nnz,)) 787 self.assertLess(err, 1e-4) 788 err = gradient_checker.compute_gradient_error( 789 dense_t, 790 dense_shape, 791 cdiv.values, (nnz,), 792 x_init_value=dense_vals_np) 793 self.assertLess(err, 2e-4) 794 795 796 class SparseSoftmaxTest(test_util.TensorFlowTestCase): 797 798 def testEquivalentToDensified(self): 799 np.random.seed(1618) 800 n, m = np.random.choice(20, size=2) 801 802 for dtype in [np.float32, np.float64]: 803 sp_vals_np = np.random.rand(n, m).astype(dtype) 804 805 batched_sp_t, unused_nnz1 = _sparsify( 806 sp_vals_np.reshape((1, n, m)), thresh=0.) # No masking. 807 808 with self.test_session(use_gpu=False): 809 densified = constant_op.constant(sp_vals_np) 810 811 sp_result = sparse_ops.sparse_softmax(batched_sp_t).eval( 812 ).values.reshape((n, m)) 813 dense_result = nn_ops.softmax(densified) 814 815 self.assertAllClose(dense_result.eval(), sp_result) 816 817 def testHigherRanks(self): 818 # For the first shape: 819 # First batch: 820 # [? e.] 821 # [1. ? ] 822 # Second batch: 823 # [e ? ] 824 # [e e ] 825 # 826 # The softmax results should be: 827 # [? 1.] [1 ?] 828 # [1. ? ] and [.5 .5] 829 # where ? means implicitly zero. 830 # 831 # The second shape: same input data, but with a higher-rank shape. 832 shapes = [[2, 2, 2], [2, 1, 2, 2]] 833 for shape in shapes: 834 values = np.asarray( 835 [0., np.e, 1., 0., np.e, 0., np.e, np.e]).reshape(shape) 836 sp_t, unused_nnz = _sparsify(values, thresh=1e-2) 837 expected_values = [1., 1., 1., .5, .5] 838 839 with self.test_session(use_gpu=False): 840 result = sparse_ops.sparse_softmax(sp_t).eval() 841 842 self.assertAllEqual(expected_values, result.values) 843 self.assertAllEqual(sp_t.indices.eval(), result.indices) 844 self.assertAllEqual(shape, result.dense_shape) 845 846 def testGradient(self): 847 x_shape = [2, 5, 10] 848 with self.test_session(use_gpu=False): 849 for dtype in [np.float32, np.float64]: 850 x_np = np.random.randn(*x_shape).astype(dtype) 851 x_tf, nnz = _sparsify(x_np) 852 y_tf = sparse_ops.sparse_softmax(x_tf) 853 err = gradient_checker.compute_gradient_error(x_tf.values, (nnz,), 854 y_tf.values, (nnz,)) 855 self.assertLess(err, 1e-4) 856 857 858 class SparseMinimumMaximumTest(test_util.TensorFlowTestCase): 859 860 def _assertSparseTensorValueEqual(self, a, b): 861 self.assertAllEqual(a.indices, b.indices) 862 self.assertAllEqual(a.values, b.values) 863 self.assertAllEqual(a.dense_shape, b.dense_shape) 864 865 def testBasic(self): 866 with self.test_session(use_gpu=False): 867 # 1-D, values at index 0. 868 sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7]) 869 sp_one = sparse_tensor.SparseTensor([[0]], [1], [7]) 870 max_tf = sparse_ops.sparse_maximum(sp_zero, sp_one).eval() 871 min_tf = sparse_ops.sparse_minimum(sp_zero, sp_one).eval() 872 self._assertSparseTensorValueEqual(sp_one.eval(), max_tf) 873 self._assertSparseTensorValueEqual(sp_zero.eval(), min_tf) 874 875 # Values at different indices. 876 sp_zero = sparse_tensor.SparseTensor([[0]], [0], [7]) 877 sp_zero_2 = sparse_tensor.SparseTensor([[1]], [0], [7]) 878 expected = sparse_tensor.SparseTensor([[0], [1]], [0, 0], [7]) 879 max_tf = sparse_ops.sparse_maximum(sp_zero, sp_zero_2).eval() 880 min_tf = sparse_ops.sparse_minimum(sp_zero, sp_zero_2).eval() 881 self._assertSparseTensorValueEqual(expected.eval(), max_tf) 882 self._assertSparseTensorValueEqual(expected.eval(), min_tf) 883 884 def testRandom(self): 885 np.random.seed(1618) 886 shapes = [(13,), (6, 8), (1, 7, 1)] 887 for shape in shapes: 888 for dtype in [np.int32, np.int64, np.float16, np.float32, np.float64]: 889 a_np = np.random.randn(*shape).astype(dtype) 890 b_np = np.random.randn(*shape).astype(dtype) 891 sp_a, unused_a_nnz = _sparsify(a_np, thresh=-.5) 892 sp_b, unused_b_nnz = _sparsify(b_np, thresh=-.5) 893 894 with self.test_session(use_gpu=False): 895 maximum_tf = sparse_ops.sparse_maximum(sp_a, sp_b) 896 maximum_tf_densified = sparse_ops.sparse_tensor_to_dense( 897 maximum_tf).eval() 898 minimum_tf = sparse_ops.sparse_minimum(sp_a, sp_b) 899 minimum_tf_densified = sparse_ops.sparse_tensor_to_dense( 900 minimum_tf).eval() 901 902 a_densified = sparse_ops.sparse_tensor_to_dense(sp_a).eval() 903 b_densified = sparse_ops.sparse_tensor_to_dense(sp_b).eval() 904 905 self.assertAllEqual( 906 np.maximum(a_densified, b_densified), maximum_tf_densified) 907 self.assertAllEqual( 908 np.minimum(a_densified, b_densified), minimum_tf_densified) 909 910 def testMismatchedShapes(self): 911 with self.test_session(use_gpu=False): 912 sp_zero = sparse_tensor.SparseTensor([[0, 0]], [0], [1, 1]) 913 sp_one = sparse_tensor.SparseTensor([[0]], [1], [2]) 914 with self.assertRaisesOpError("Operands do not have the same ranks"): 915 sparse_ops.sparse_maximum(sp_zero, sp_one).eval() 916 917 sp_zero = sparse_tensor.SparseTensor([[0]], [0], [1]) 918 sp_one = sparse_tensor.SparseTensor([[0]], [1], [2]) 919 with self.assertRaisesOpError("Operands' shapes do not match"): 920 sparse_ops.sparse_maximum(sp_zero, sp_one).eval() 921 922 923 class SparseTransposeTest(test.TestCase): 924 925 def testTranspose(self): 926 if np.__version__ == "1.13.0": 927 self.skipTest("numpy 1.13.0 bug") 928 929 with self.test_session(use_gpu=False): 930 np.random.seed(1618) 931 shapes = [np.random.randint(1, 10, size=rank) for rank in range(1, 6)] 932 for shape in shapes: 933 for dtype in [np.int32, np.int64, np.float32, np.float64]: 934 dn_input = np.random.randn(*shape).astype(dtype) 935 rank = array_ops.rank(dn_input).eval() 936 perm = np.random.choice(rank, rank, False) 937 sp_input, unused_a_nnz = _sparsify(dn_input) 938 sp_trans = sparse_ops.sparse_transpose(sp_input, perm=perm) 939 dn_trans = sparse_ops.sparse_tensor_to_dense(sp_trans).eval() 940 expected_trans = array_ops.transpose(dn_input, perm=perm).eval() 941 self.assertAllEqual(expected_trans.shape, sp_trans.get_shape()) 942 self.assertAllEqual(dn_trans, expected_trans) 943 944 945 class SparsePlaceholderTest(test.TestCase): 946 947 def testPlaceholder(self): 948 foo = array_ops.sparse_placeholder(dtypes.float32, shape=(10, 47)) 949 self.assertAllEqual([10, 47], foo.get_shape()) 950 self.assertAllEqual([None, 2], foo.indices.get_shape().as_list()) 951 952 def testPartialShapePlaceholder(self): 953 foo = array_ops.sparse_placeholder(dtypes.float32, shape=(None, 47)) 954 self.assertAllEqual([None, None], foo.get_shape().as_list()) 955 self.assertAllEqual([None, 2], foo.indices.get_shape().as_list()) 956 957 def testNoShapePlaceholder(self): 958 foo = array_ops.sparse_placeholder(dtypes.float32, shape=None) 959 self.assertAllEqual(None, foo.get_shape()) 960 self.assertAllEqual([None, None], foo.indices.get_shape().as_list()) 961 962 963 if __name__ == "__main__": 964 googletest.main() 965