test_sparse_utils_op.py 19.4 KB
Newer Older
1
# Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
2
#
3 4 5
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
6
#
7
#     http://www.apache.org/licenses/LICENSE-2.0
8
#
9 10 11 12 13 14 15 16 17
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest
import numpy as np
import paddle
18
import paddle.fluid as fluid
19
import paddle.fluid.core as core
20 21
from paddle.fluid.framework import _test_eager_guard

22 23
devices = ['cpu', 'gpu']

24

25 26
class TestSparseCreate(unittest.TestCase):
    def test_create_coo_by_tensor(self):
27
        with _test_eager_guard():
28 29
            indices = [[0, 0, 1, 2, 2], [1, 3, 2, 0, 1]]
            values = [1, 2, 3, 4, 5]
30
            dense_shape = [3, 4]
31 32
            dense_indices = paddle.to_tensor(indices)
            dense_elements = paddle.to_tensor(values, dtype='float32')
33 34 35
            coo = paddle.sparse.sparse_coo_tensor(
                dense_indices, dense_elements, dense_shape, stop_gradient=False
            )
36
            # test the to_string.py
37 38
            assert np.array_equal(indices, coo.indices().numpy())
            assert np.array_equal(values, coo.values().numpy())
39

40 41 42 43
    def test_create_coo_by_np(self):
        with _test_eager_guard():
            indices = [[0, 1, 2], [1, 2, 0]]
            values = [1.0, 2.0, 3.0]
44
            dense_shape = [3, 3]
45
            coo = paddle.sparse.sparse_coo_tensor(indices, values, dense_shape)
46
            assert np.array_equal(3, coo.nnz())
47 48
            assert np.array_equal(indices, coo.indices().numpy())
            assert np.array_equal(values, coo.values().numpy())
49

50
    def test_create_csr_by_tensor(self):
51
        with _test_eager_guard():
52 53 54
            crows = [0, 2, 3, 5]
            cols = [1, 3, 2, 0, 1]
            values = [1, 2, 3, 4, 5]
55
            dense_shape = [3, 4]
56 57 58
            dense_crows = paddle.to_tensor(crows)
            dense_cols = paddle.to_tensor(cols)
            dense_elements = paddle.to_tensor(values, dtype='float32')
59
            stop_gradient = False
60 61 62 63 64 65 66
            csr = paddle.sparse.sparse_csr_tensor(
                dense_crows,
                dense_cols,
                dense_elements,
                dense_shape,
                stop_gradient=stop_gradient,
            )
67

68 69 70 71 72 73
    def test_create_csr_by_np(self):
        with _test_eager_guard():
            crows = [0, 2, 3, 5]
            cols = [1, 3, 2, 0, 1]
            values = [1, 2, 3, 4, 5]
            dense_shape = [3, 4]
74 75 76
            csr = paddle.sparse.sparse_csr_tensor(
                crows, cols, values, dense_shape
            )
77
            # test the to_string.py
78
            assert np.array_equal(5, csr.nnz())
79 80 81
            assert np.array_equal(crows, csr.crows().numpy())
            assert np.array_equal(cols, csr.cols().numpy())
            assert np.array_equal(values, csr.values().numpy())
82 83 84 85 86 87 88

    def test_place(self):
        with _test_eager_guard():
            place = core.CPUPlace()
            indices = [[0, 1], [0, 1]]
            values = [1.0, 2.0]
            dense_shape = [2, 2]
89 90 91
            coo = paddle.sparse.sparse_coo_tensor(
                indices, values, dense_shape, place=place
            )
92
            assert coo.place.is_cpu_place()
93 94
            assert coo.values().place.is_cpu_place()
            assert coo.indices().place.is_cpu_place()
95 96 97 98

            crows = [0, 2, 3, 5]
            cols = [1, 3, 2, 0, 1]
            values = [1.0, 2.0, 3.0, 4.0, 5.0]
99 100 101
            csr = paddle.sparse.sparse_csr_tensor(
                crows, cols, values, [3, 5], place=place
            )
102
            assert csr.place.is_cpu_place()
103 104 105
            assert csr.crows().place.is_cpu_place()
            assert csr.cols().place.is_cpu_place()
            assert csr.values().place.is_cpu_place()
106 107 108 109 110 111 112 113

    def test_dtype(self):
        with _test_eager_guard():
            indices = [[0, 1], [0, 1]]
            values = [1.0, 2.0]
            dense_shape = [2, 2]
            indices = paddle.to_tensor(indices, dtype='int32')
            values = paddle.to_tensor(values, dtype='float32')
114 115 116
            coo = paddle.sparse.sparse_coo_tensor(
                indices, values, dense_shape, dtype='float64'
            )
117 118 119 120 121
            assert coo.dtype == paddle.float64

            crows = [0, 2, 3, 5]
            cols = [1, 3, 2, 0, 1]
            values = [1.0, 2.0, 3.0, 4.0, 5.0]
122 123 124
            csr = paddle.sparse.sparse_csr_tensor(
                crows, cols, values, [3, 5], dtype='float16'
            )
125 126 127 128 129 130 131 132
            assert csr.dtype == paddle.float16

    def test_create_coo_no_shape(self):
        with _test_eager_guard():
            indices = [[0, 1], [0, 1]]
            values = [1.0, 2.0]
            indices = paddle.to_tensor(indices, dtype='int32')
            values = paddle.to_tensor(values, dtype='float32')
133
            coo = paddle.sparse.sparse_coo_tensor(indices, values)
134 135 136 137
            assert [2, 2] == coo.shape


class TestSparseConvert(unittest.TestCase):
138 139 140
    def test_to_sparse_coo(self):
        with _test_eager_guard():
            x = [[0, 1, 0, 2], [0, 0, 3, 0], [4, 5, 0, 0]]
141 142 143
            indices = [[0, 0, 1, 2, 2], [1, 3, 2, 0, 1]]
            values = [1.0, 2.0, 3.0, 4.0, 5.0]
            dense_x = paddle.to_tensor(x, dtype='float32', stop_gradient=False)
144
            out = dense_x.to_sparse_coo(2)
145 146
            assert np.array_equal(out.indices().numpy(), indices)
            assert np.array_equal(out.values().numpy(), values)
147
            # test to_sparse_coo_grad backward
148 149
            out_grad_indices = [[0, 1], [0, 1]]
            out_grad_values = [2.0, 3.0]
150
            out_grad = paddle.sparse.sparse_coo_tensor(
151
                paddle.to_tensor(out_grad_indices),
152 153
                paddle.to_tensor(out_grad_values),
                shape=out.shape,
154 155
                stop_gradient=True,
            )
156
            out.backward(out_grad)
157 158 159
            assert np.array_equal(
                dense_x.grad.numpy(), out_grad.to_dense().numpy()
            )
160 161

    def test_coo_to_dense(self):
162
        fluid.set_flags({"FLAGS_retain_grad_for_all_tensor": True})
163 164 165
        with _test_eager_guard():
            indices = [[0, 0, 1, 2, 2], [1, 3, 2, 0, 1]]
            values = [1.0, 2.0, 3.0, 4.0, 5.0]
166 167
            indices_dtypes = ['int32', 'int64']
            for indices_dtype in indices_dtypes:
168
                sparse_x = paddle.sparse.sparse_coo_tensor(
169 170 171
                    paddle.to_tensor(indices, dtype=indices_dtype),
                    paddle.to_tensor(values),
                    shape=[3, 4],
172 173
                    stop_gradient=False,
                )
174
                dense_tensor = sparse_x.to_dense()
175 176 177 178 179 180
                # test to_dense_grad backward
                out_grad = [
                    [1.0, 2.0, 3.0, 4.0],
                    [5.0, 6.0, 7.0, 8.0],
                    [9.0, 10.0, 11.0, 12.0],
                ]
181
                dense_tensor.backward(paddle.to_tensor(out_grad))
182
                # mask the out_grad by sparse_x.indices()
183
                correct_x_grad = [2.0, 4.0, 7.0, 9.0, 10.0]
184 185 186
                assert np.array_equal(
                    correct_x_grad, sparse_x.grad.values().numpy()
                )
187 188

                paddle.device.set_device("cpu")
189
                sparse_x_cpu = paddle.sparse.sparse_coo_tensor(
190 191 192
                    paddle.to_tensor(indices, dtype=indices_dtype),
                    paddle.to_tensor(values),
                    shape=[3, 4],
193 194
                    stop_gradient=False,
                )
195 196
                dense_tensor_cpu = sparse_x_cpu.to_dense()
                dense_tensor_cpu.backward(paddle.to_tensor(out_grad))
197 198 199
                assert np.array_equal(
                    correct_x_grad, sparse_x_cpu.grad.values().numpy()
                )
200
        fluid.set_flags({"FLAGS_retain_grad_for_all_tensor": False})
201

202 203 204
    def test_to_sparse_csr(self):
        with _test_eager_guard():
            x = [[0, 1, 0, 2], [0, 0, 3, 0], [4, 5, 0, 0]]
205 206 207
            crows = [0, 2, 3, 5]
            cols = [1, 3, 2, 0, 1]
            values = [1, 2, 3, 4, 5]
208
            dense_x = paddle.to_tensor(x)
209
            out = dense_x.to_sparse_csr()
210 211 212
            assert np.array_equal(out.crows().numpy(), crows)
            assert np.array_equal(out.cols().numpy(), cols)
            assert np.array_equal(out.values().numpy(), values)
213

214
            dense_tensor = out.to_dense()
215 216
            assert np.array_equal(dense_tensor.numpy(), x)

217
    def test_coo_values_grad(self):
218
        fluid.set_flags({"FLAGS_retain_grad_for_all_tensor": True})
219 220 221
        with _test_eager_guard():
            indices = [[0, 0, 1, 2, 2], [1, 3, 2, 0, 1]]
            values = [1.0, 2.0, 3.0, 4.0, 5.0]
222
            sparse_x = paddle.sparse.sparse_coo_tensor(
223
                paddle.to_tensor(indices),
224 225
                paddle.to_tensor(values),
                shape=[3, 4],
226 227
                stop_gradient=False,
            )
228 229 230 231 232
            values_tensor = sparse_x.values()
            out_grad = [2.0, 3.0, 5.0, 8.0, 9.0]
            # test coo_values_grad
            values_tensor.backward(paddle.to_tensor(out_grad))
            assert np.array_equal(out_grad, sparse_x.grad.values().numpy())
233
            indices = [[0, 0, 1, 2, 2], [1, 3, 2, 0, 1]]
234 235 236 237 238 239 240
            values = [
                [1.0, 1.0],
                [2.0, 2.0],
                [3.0, 3.0],
                [4.0, 4.0],
                [5.0, 5.0],
            ]
241
            sparse_x = paddle.sparse.sparse_coo_tensor(
242 243 244
                paddle.to_tensor(indices),
                paddle.to_tensor(values),
                shape=[3, 4, 2],
245 246
                stop_gradient=False,
            )
247
            values_tensor = sparse_x.values()
248 249 250 251 252 253 254
            out_grad = [
                [2.0, 2.0],
                [3.0, 3.0],
                [5.0, 5.0],
                [8.0, 8.0],
                [9.0, 9.0],
            ]
255 256 257
            # test coo_values_grad
            values_tensor.backward(paddle.to_tensor(out_grad))
            assert np.array_equal(out_grad, sparse_x.grad.values().numpy())
258
        fluid.set_flags({"FLAGS_retain_grad_for_all_tensor": False})
259

260 261
    def test_sparse_coo_tensor_grad(self):
        with _test_eager_guard():
262
            for device in devices:
263 264 265
                if device == 'cpu' or (
                    device == 'gpu' and paddle.is_compiled_with_cuda()
                ):
266 267 268 269
                    paddle.device.set_device(device)
                    indices = [[0, 1], [0, 1]]
                    values = [1, 2]
                    indices = paddle.to_tensor(indices, dtype='int32')
270 271 272
                    values = paddle.to_tensor(
                        values, dtype='float32', stop_gradient=False
                    )
273
                    sparse_x = paddle.sparse.sparse_coo_tensor(
274 275
                        indices, values, shape=[2, 2], stop_gradient=False
                    )
276 277 278 279
                    grad_indices = [[0, 1], [1, 1]]
                    grad_values = [2, 3]
                    grad_indices = paddle.to_tensor(grad_indices, dtype='int32')
                    grad_values = paddle.to_tensor(grad_values, dtype='float32')
280
                    sparse_out_grad = paddle.sparse.sparse_coo_tensor(
281 282
                        grad_indices, grad_values, shape=[2, 2]
                    )
283 284
                    sparse_x.backward(sparse_out_grad)
                    correct_values_grad = [0, 3]
285 286 287
                    assert np.array_equal(
                        correct_values_grad, values.grad.numpy()
                    )
288

289 290
                    # test the non-zero values is a vector
                    values = [[1, 1], [2, 2]]
291 292 293
                    values = paddle.to_tensor(
                        values, dtype='float32', stop_gradient=False
                    )
294
                    sparse_x = paddle.sparse.sparse_coo_tensor(
295 296
                        indices, values, shape=[2, 2, 2], stop_gradient=False
                    )
297 298
                    grad_values = [[2, 2], [3, 3]]
                    grad_values = paddle.to_tensor(grad_values, dtype='float32')
299
                    sparse_out_grad = paddle.sparse.sparse_coo_tensor(
300 301
                        grad_indices, grad_values, shape=[2, 2, 2]
                    )
302 303
                    sparse_x.backward(sparse_out_grad)
                    correct_values_grad = [[0, 0], [3, 3]]
304 305 306
                    assert np.array_equal(
                        correct_values_grad, values.grad.numpy()
                    )
307

308 309 310
    def test_sparse_coo_tensor_sorted(self):
        with _test_eager_guard():
            for device in devices:
311 312 313
                if device == 'cpu' or (
                    device == 'gpu' and paddle.is_compiled_with_cuda()
                ):
314
                    paddle.device.set_device(device)
315
                    # test unsorted and duplicate indices
316 317 318 319
                    indices = [[1, 0, 0], [0, 1, 1]]
                    values = [1.0, 2.0, 3.0]
                    indices = paddle.to_tensor(indices, dtype='int32')
                    values = paddle.to_tensor(values, dtype='float32')
320 321
                    sparse_x = paddle.sparse.sparse_coo_tensor(indices, values)
                    sparse_x = paddle.sparse.coalesce(sparse_x)
322 323
                    indices_sorted = [[0, 1], [1, 0]]
                    values_sorted = [5.0, 1.0]
324 325 326 327 328 329
                    assert np.array_equal(
                        indices_sorted, sparse_x.indices().numpy()
                    )
                    assert np.array_equal(
                        values_sorted, sparse_x.values().numpy()
                    )
330

331 332 333
                    # test the non-zero values is a vector
                    values = [[1.0, 1.0], [2.0, 2.0], [3.0, 3.0]]
                    values = paddle.to_tensor(values, dtype='float32')
334 335
                    sparse_x = paddle.sparse.sparse_coo_tensor(indices, values)
                    sparse_x = paddle.sparse.coalesce(sparse_x)
336
                    values_sorted = [[5.0, 5.0], [1.0, 1.0]]
337 338 339 340 341 342
                    assert np.array_equal(
                        indices_sorted, sparse_x.indices().numpy()
                    )
                    assert np.array_equal(
                        values_sorted, sparse_x.values().numpy()
                    )
343

Z
zhangkaihuo 已提交
344 345
    def test_batch_csr(self):
        with _test_eager_guard():
Z
zhangkaihuo 已提交
346 347 348 349 350 351 352 353 354 355 356 357

            def verify(dense_x):
                sparse_x = dense_x.to_sparse_csr()
                out = sparse_x.to_dense()
                assert np.allclose(out.numpy(), dense_x.numpy())

            shape = np.random.randint(low=1, high=10, size=3)
            shape = list(shape)
            dense_x = paddle.randn(shape)
            dense_x = paddle.nn.functional.dropout(dense_x, p=0.5)
            verify(dense_x)

358
            # test batchs=1
Z
zhangkaihuo 已提交
359 360 361 362 363
            shape[0] = 1
            dense_x = paddle.randn(shape)
            dense_x = paddle.nn.functional.dropout(dense_x, p=0.5)
            verify(dense_x)

Z
zhangkaihuo 已提交
364
            shape = np.random.randint(low=3, high=10, size=3)
Z
zhangkaihuo 已提交
365 366
            shape = list(shape)
            dense_x = paddle.randn(shape)
367
            # set the 0th batch to zero
Z
zhangkaihuo 已提交
368 369 370 371
            dense_x[0] = 0
            verify(dense_x)

            dense_x = paddle.randn(shape)
372
            # set the 1th batch to zero
Z
zhangkaihuo 已提交
373 374 375 376
            dense_x[1] = 0
            verify(dense_x)

            dense_x = paddle.randn(shape)
377
            # set the 2th batch to zero
Z
zhangkaihuo 已提交
378 379
            dense_x[2] = 0
            verify(dense_x)
Z
zhangkaihuo 已提交
380

381 382 383 384 385 386 387 388 389

class TestCooError(unittest.TestCase):
    def test_small_shape(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                indices = [[2, 3], [0, 2]]
                values = [1, 2]
                # 1. the shape too small
                dense_shape = [2, 2]
390 391 392
                sparse_x = paddle.sparse.sparse_coo_tensor(
                    indices, values, shape=dense_shape
                )
393 394 395 396 397 398 399

    def test_same_nnz(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                # 2. test the nnz of indices must same as nnz of values
                indices = [[1, 2], [1, 0]]
                values = [1, 2, 3]
400
                sparse_x = paddle.sparse.sparse_coo_tensor(indices, values)
401 402 403 404 405 406 407

    def test_same_dimensions(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                indices = [[1, 2], [1, 0]]
                values = [1, 2, 3]
                shape = [2, 3, 4]
408 409 410
                sparse_x = paddle.sparse.sparse_coo_tensor(
                    indices, values, shape=shape
                )
411 412 413 414 415 416

    def test_indices_dtype(self):
        with _test_eager_guard():
            with self.assertRaises(TypeError):
                indices = [[1.0, 2.0], [0, 1]]
                values = [1, 2]
417
                sparse_x = paddle.sparse.sparse_coo_tensor(indices, values)
418 419 420 421 422 423 424 425 426 427


class TestCsrError(unittest.TestCase):
    def test_dimension1(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [0, 1, 2, 3]
                cols = [0, 1, 2]
                values = [1, 2, 3]
                shape = [3]
428
                sparse_x = paddle.sparse.sparse_csr_tensor(
429 430
                    crows, cols, values, shape
                )
431 432 433 434 435 436 437 438

    def test_dimension2(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [0, 1, 2, 3]
                cols = [0, 1, 2]
                values = [1, 2, 3]
                shape = [3, 3, 3, 3]
439
                sparse_x = paddle.sparse.sparse_csr_tensor(
440 441
                    crows, cols, values, shape
                )
442 443 444 445 446 447 448 449

    def test_same_shape1(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [0, 1, 2, 3]
                cols = [0, 1, 2, 3]
                values = [1, 2, 3]
                shape = [3, 4]
450
                sparse_x = paddle.sparse.sparse_csr_tensor(
451 452
                    crows, cols, values, shape
                )
453

454 455 456 457 458 459 460
    def test_same_shape2(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [0, 1, 2, 3]
                cols = [0, 1, 2, 3]
                values = [1, 2, 3, 4]
                shape = [3, 4]
461
                sparse_x = paddle.sparse.sparse_csr_tensor(
462 463
                    crows, cols, values, shape
                )
464 465 466 467 468 469 470 471

    def test_same_shape3(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [0, 1, 2, 3, 0, 1, 2]
                cols = [0, 1, 2, 3, 0, 1, 2]
                values = [1, 2, 3, 4, 0, 1, 2]
                shape = [2, 3, 4]
472
                sparse_x = paddle.sparse.sparse_csr_tensor(
473 474
                    crows, cols, values, shape
                )
475 476 477 478 479 480 481 482

    def test_crows_first_value(self):
        with _test_eager_guard():
            with self.assertRaises(ValueError):
                crows = [1, 1, 2, 3]
                cols = [0, 1, 2]
                values = [1, 2, 3]
                shape = [3, 4]
483
                sparse_x = paddle.sparse.sparse_csr_tensor(
484 485
                    crows, cols, values, shape
                )
486 487 488 489 490 491 492 493

    def test_dtype(self):
        with _test_eager_guard():
            with self.assertRaises(TypeError):
                crows = [0, 1, 2, 3.0]
                cols = [0, 1, 2]
                values = [1, 2, 3]
                shape = [3]
494
                sparse_x = paddle.sparse.sparse_csr_tensor(
495 496
                    crows, cols, values, shape
                )
497

498 499 500

if __name__ == "__main__":
    unittest.main()