Files
paddlepaddle--paddle/test/legacy_test/test_sparse_pca_lowrank.py
T
2026-07-13 12:40:42 +08:00

135 lines
4.4 KiB
Python

# Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved.
#
# 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
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# 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 random
import unittest
import numpy as np
from op_test import is_custom_device
import paddle
class TestSparsePcaLowrankAPI(unittest.TestCase):
def transpose(self, x):
shape = x.shape
perm = list(range(0, len(shape)))
perm = [*perm[:-2], perm[-1], perm[-2]]
return paddle.transpose(x, perm)
def random_sparse_matrix(self, rows, columns, density=0.01, **kwargs):
dtype = kwargs.get('dtype', paddle.float64)
nonzero_elements = max(
min(rows, columns), int(rows * columns * density)
)
row_indices = [i % rows for i in range(nonzero_elements)]
column_indices = [i % columns for i in range(nonzero_elements)]
random.shuffle(column_indices)
indices = [row_indices, column_indices]
values = paddle.randn((nonzero_elements,), dtype=dtype)
values *= paddle.to_tensor(
[-(float(i - j) ** 2) for i, j in zip(*indices)], dtype=dtype
).exp()
indices_tensor = paddle.to_tensor(indices)
x = paddle.sparse.sparse_coo_tensor(
indices_tensor, values, (rows, columns)
)
return paddle.sparse.coalesce(x)
def run_subtest(self, guess_rank, matrix_size, batches, pca, **options):
density = options.pop('density', 0.5)
if isinstance(matrix_size, int):
rows = columns = matrix_size
else:
rows, columns = matrix_size
a_input = self.random_sparse_matrix(rows, columns, density)
a = a_input.to_dense()
u, s, v = pca(a_input, q=guess_rank, **options)
self.assertEqual(s.shape[-1], guess_rank)
self.assertEqual(u.shape[-2], rows)
self.assertEqual(u.shape[-1], guess_rank)
self.assertEqual(v.shape[-1], guess_rank)
self.assertEqual(v.shape[-2], columns)
A1 = u.matmul(paddle.nn.functional.diag_embed(s)).matmul(
self.transpose(v)
)
ones_m1 = paddle.ones((*batches, rows, 1), dtype=a.dtype)
c = a.sum(axis=-2) / rows
c = c.reshape((*batches, 1, columns))
A2 = a - ones_m1.matmul(c)
np.testing.assert_allclose(A1.numpy(), A2.numpy(), atol=1e-5)
@unittest.skipIf(
not (paddle.is_compiled_with_cuda() or is_custom_device())
or paddle.is_compiled_with_rocm(),
"only support cuda",
)
def test_sparse(self):
pca_lowrank = paddle.sparse.pca_lowrank
for guess_rank, size in [
(4, (17, 4)),
(4, (4, 17)),
(16, (17, 17)),
(21, (100, 40)),
]:
for density in [0.005, 0.01]:
self.run_subtest(
guess_rank, size, (), pca_lowrank, density=density
)
def test_errors(self):
pca_lowrank = paddle.sparse.pca_lowrank
x = np.random.randn(5, 5).astype('float64')
dense_x = paddle.to_tensor(x)
sparse_x = dense_x.to_sparse_coo(len(x.shape))
def test_x_not_tensor():
U, S, V = pca_lowrank(x)
self.assertRaises(ValueError, test_x_not_tensor)
def test_x_not_sparse():
U, S, V = pca_lowrank(sparse_x.to_dense())
self.assertRaises(ValueError, test_x_not_sparse)
def test_q_range():
q = -1
U, S, V = pca_lowrank(sparse_x, q)
self.assertRaises(ValueError, test_q_range)
def test_niter_range():
n = -1
U, S, V = pca_lowrank(sparse_x, niter=n)
self.assertRaises(ValueError, test_niter_range)
def test_x_wrong_shape():
x = np.random.randn(5, 5, 5).astype('float64')
dense_x = paddle.to_tensor(x)
sparse_x = dense_x.to_sparse_coo(len(x.shape))
U, S, V = pca_lowrank(sparse_x)
self.assertRaises(ValueError, test_x_wrong_shape)
if __name__ == "__main__":
unittest.main()