1# Copyright 2018 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 sparse ops.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21from absl.testing import parameterized 22import numpy as np 23 24from tensorflow.python.framework import constant_op 25from tensorflow.python.framework import dtypes 26from tensorflow.python.framework import ops 27from tensorflow.python.framework import sparse_tensor 28from tensorflow.python.framework import test_util 29# Need array_grad to register gradient for Identity. 30from tensorflow.python.ops import array_grad # pylint: disable=unused-import 31from tensorflow.python.ops import array_ops 32from tensorflow.python.ops import gradient_checker_v2 as gradient_checker 33from tensorflow.python.ops import math_ops 34# Need sparse_grad to register gradient for SparseToDense. 35from tensorflow.python.ops import sparse_grad # pylint: disable=unused-import 36from tensorflow.python.ops import sparse_ops 37from tensorflow.python.platform import googletest 38 39 40@test_util.run_all_in_graph_and_eager_modes 41class SparseOpsTest(test_util.TensorFlowTestCase, parameterized.TestCase): 42 43 def testSparseEye(self): 44 def test_one(n, m, as_tensors): 45 expected = np.eye(n, m) 46 if as_tensors: 47 m = constant_op.constant(m) 48 n = constant_op.constant(n) 49 s = sparse_ops.sparse_eye(n, m) 50 d = sparse_ops.sparse_to_dense(s.indices, s.dense_shape, s.values) 51 self.assertAllEqual(self.evaluate(d), expected) 52 53 for n in range(2, 10, 2): 54 for m in range(2, 10, 2): 55 # Test with n and m as both constants and tensors. 56 test_one(n, m, True) 57 test_one(n, m, False) 58 59 def testDenseFromConstantToSparse(self): 60 expected_constant = np.reshape(np.arange(24, dtype=np.int64), (3, 4, 2)) 61 tensor = constant_op.constant(expected_constant) 62 sparse = sparse_ops.from_dense(tensor) 63 dense = sparse_ops.sparse_to_dense(sparse.indices, sparse.dense_shape, 64 sparse.values) 65 constant = self.evaluate(dense) 66 self.assertAllEqual(expected_constant, constant) 67 68 def testTransposePreservesShape(self): 69 with ops.Graph().as_default(): 70 t = sparse_tensor.SparseTensor(indices=[[0, 0]], 71 values=[0.], 72 dense_shape=[3, 4]) 73 self.assertTrue(t.shape.is_fully_defined) 74 transposed = sparse_ops.sparse_transpose(t) 75 self.assertAllEqual(transposed.shape, [4, 3]) 76 77 def testSparseExpandDims(self): 78 for rank in range(1, 4): 79 # Create a dummy input. When rank=3, shape=[2, 4, 6]. 80 shape = np.arange(1, rank + 1) * 2 81 before = np.arange(np.prod(shape)).reshape(shape) 82 83 # Make entries sparse. 84 before *= np.random.binomial(1, .2, before.shape) 85 dense_shape = before.shape 86 indices = np.array(np.where(before)).T 87 values = before[before != 0] 88 89 # Try every possible valid value of axis. 90 for axis in range(-rank - 1, rank): 91 expected_after = np.expand_dims(before, axis) 92 93 for axis_as_tensor in [False, True]: 94 dense_shape_t = constant_op.constant(dense_shape, dtype=dtypes.int64) 95 indices_t = constant_op.constant(indices) 96 values_t = constant_op.constant(values) 97 before_t = sparse_tensor.SparseTensor( 98 indices=indices_t, values=values_t, dense_shape=dense_shape_t) 99 100 if axis_as_tensor: 101 axis = constant_op.constant(axis) 102 103 s = sparse_ops.sparse_expand_dims(before_t, axis) 104 d = sparse_ops.sparse_to_dense(s.indices, s.dense_shape, s.values) 105 self.assertAllEqual(self.evaluate(d), expected_after) 106 107 @parameterized.parameters([ 108 (math_ops.abs, [1.0, -1.0, 3.0, -4.0], [1.0, 1.0, 3.0, 4.0]), 109 (math_ops.negative, [1.0, -1.0, 3.0, -4.0], [-1.0, 1.0, -3.0, 4.0]), 110 (math_ops.sign, [3.0, -2.0, 0.0, -4.0], [1.0, -1.0, 0.0, -1.0]), 111 (math_ops.square, [1.0, -1.0, 3.0, -4.0], [1.0, 1.0, 9.0, 16.0]), 112 ]) 113 def testUnarySparseDispatch(self, op, values, expected): 114 st = sparse_tensor.SparseTensor( 115 indices=[[0, 0], [0, 1], [2, 0], [2, 4]], 116 values=values, 117 dense_shape=[3, 6]) 118 result = op(st) 119 result_value = self.evaluate(result) 120 self.assertAllEqual(result_value.indices, st.indices) 121 self.assertAllEqual(result_value.values, expected) 122 self.assertAllEqual(result_value.dense_shape, st.dense_shape) 123 124 def testSparseToDenseGradient(self): 125 126 def f(sparse_values, default_value): 127 st = sparse_tensor.SparseTensor( 128 indices=[[0, 3, 6], [1, 4, 7], [2, 5, 8]], 129 values=sparse_values, 130 dense_shape=[3, 6, 9]) 131 return sparse_ops.sparse_tensor_to_dense(st, default_value) 132 133 grads = gradient_checker.compute_gradient( 134 f, [constant_op.constant([1.0, 2.0, 3.0]), 135 constant_op.constant(0.0)]) 136 epsilon = 1e-4 137 self.assertLess(gradient_checker.max_error(*grads), epsilon) 138 139 def testSparseTensorToDenseString(self): 140 sp = sparse_tensor.SparseTensor( 141 indices=[[0, 0], [1, 2]], values=['a', 'b'], dense_shape=[2, 3]) 142 dense = sparse_ops.sparse_tensor_to_dense(sp) 143 expected_dense = [[b'a', b'', b''], [b'', b'', b'b']] 144 result_dense = self.evaluate(dense) 145 self.assertAllEqual(expected_dense, result_dense) 146 147 def testDenseSparseTensorMatMul(self): 148 149 np.random.seed(42) 150 dense_numpy_array = np.random.rand(3, 3) 151 independent_dense_tf = constant_op.constant( 152 dense_numpy_array, dtype='float32') 153 154 sp = sparse_tensor.SparseTensor( 155 indices=[[0, 0], [1, 2]], values=[4., 8.], dense_shape=[3, 3]) 156 dense_of_sparse = sparse_ops.sparse_to_dense(sp.indices, sp.shape, 157 sp.values) 158 159 result = sparse_ops.sparse_tensor_dense_matmul( 160 independent_dense_tf, sp, adjoint_a=False, adjoint_b=False) 161 expected = math_ops.matmul(independent_dense_tf, dense_of_sparse) 162 self.assertAllEqual(expected, result) 163 164 result = sparse_ops.sparse_tensor_dense_matmul( 165 independent_dense_tf, sp, adjoint_a=False, adjoint_b=True) 166 expected = math_ops.matmul(independent_dense_tf, 167 array_ops.transpose(dense_of_sparse)) 168 self.assertAllEqual(expected, result) 169 170 result = sparse_ops.sparse_tensor_dense_matmul( 171 independent_dense_tf, sp, adjoint_a=True, adjoint_b=False) 172 expected = math_ops.matmul( 173 array_ops.transpose(independent_dense_tf), dense_of_sparse) 174 self.assertAllEqual(expected, result) 175 176 result = sparse_ops.sparse_tensor_dense_matmul( 177 independent_dense_tf, sp, adjoint_a=True, adjoint_b=True) 178 expected = math_ops.matmul( 179 array_ops.transpose(independent_dense_tf), 180 array_ops.transpose(dense_of_sparse)) 181 self.assertAllEqual(expected, result) 182 183 184if __name__ == '__main__': 185 googletest.main() 186