From 28e74b1e5fe0090b6df25037e1c5ad40b2903485 Mon Sep 17 00:00:00 2001 From: hezhenhao1 Date: Thu, 10 Mar 2022 15:23:12 +0800 Subject: [PATCH] Fix sparse check and refactor the test cases of cg method. --- mindspore/python/mindspore/scipy/utils.py | 20 ++++-- tests/st/scipy_st/sparse/test_linalg.py | 81 ++++++++--------------- tests/st/scipy_st/utils.py | 30 +++------ 3 files changed, 48 insertions(+), 83 deletions(-) diff --git a/mindspore/python/mindspore/scipy/utils.py b/mindspore/python/mindspore/scipy/utils.py index 3e656768bdf..23feca498ac 100644 --- a/mindspore/python/mindspore/scipy/utils.py +++ b/mindspore/python/mindspore/scipy/utils.py @@ -164,30 +164,36 @@ def _sparse_check(func_name, a, m, b, x0): _mstype_check(func_name, x0, mstype.tensor_type, 'x0') # Checking shape and dtype - if b.ndim != 1 or (b.ndim == 2 and b.shape[1] != 1): + if (b.ndim != 1 and b.ndim != 2) or (b.ndim == 2 and b.shape[1] != 1): _raise_value_error( - "For: '", func_name, "', the shape of b should be like (N,) or (N, 1), bug got ", b.shape, ".") + "For: '", func_name, "', the shape of 'b' should be like (N,) or (N, 1), bug got ", b.shape, ".") + if (x0.ndim != 1 and x0.ndim != 2) or (x0.ndim == 2 and x0.shape[1] != 1): + _raise_value_error( + "For: '", func_name, "', the shape of 'x0' should be like (N,) or (N, 1), bug got ", x0.shape, ".") _dtype_check(func_name, b, [mstype.int32, mstype.int64, mstype.float32, mstype.float64], 'b') - _super_check((b.dtype, x0.dtype), (func_name, 'b', 'x0', 'data type'), '==', 'match', None, True) - _super_check((b.shape, x0.shape), (func_name, 'b', 'x0', 'shape'), '==', 'match', None, True) + _dtype_check(func_name, x0, [mstype.int32, mstype.int64, mstype.float32, mstype.float64], 'x0') def _check(arg, arg_name): if _callable_const(F.typeof(arg)): return arg - _solve_check(func_name, arg, b, arg_name, 'b', True) if isinstance(arg, CSRTensor): _dtype_check(func_name, arg.indptr, [mstype.int32], arg_name) _dtype_check(func_name, arg.indices, [mstype.int32], arg_name) _dtype_check(func_name, arg.values, [mstype.float32], arg_name) else: _dtype_check(func_name, arg, [mstype.int32, mstype.int64, mstype.float32, mstype.float64], arg_name) - if F.dtype(arg) in (mstype.int32, mstype.int64): - arg = F.cast(arg, mstype.float64) + + _solve_check(func_name, arg, b, arg_name, 'b', True) + _solve_check(func_name, arg, x0, arg_name, 'x0', True) + if isinstance(arg, Tensor) and F.dtype(arg) in (mstype.int32, mstype.int64): + arg = F.cast(arg, mstype.float64) return arg a = _check(a, 'A') m = _check(m, 'M') + b = b.ravel() + x0 = x0.ravel() if F.dtype(b) in (mstype.int32, mstype.int64): b = F.cast(b, mstype.float64) x0 = F.cast(x0, mstype.float64) diff --git a/tests/st/scipy_st/sparse/test_linalg.py b/tests/st/scipy_st/sparse/test_linalg.py index c2fb228e032..67c72716235 100644 --- a/tests/st/scipy_st/sparse/test_linalg.py +++ b/tests/st/scipy_st/sparse/test_linalg.py @@ -21,9 +21,8 @@ import mindspore.ops as ops import mindspore.nn as nn import mindspore.scipy as msp from mindspore import context -from mindspore.common import Tensor, CSRTensor -from tests.st.scipy_st.utils import create_sym_pos_matrix, create_full_rank_matrix, create_sym_pos_sparse_matrix, \ - to_tensor +from mindspore.common import Tensor +from tests.st.scipy_st.utils import create_sym_pos_matrix, create_full_rank_matrix, to_tensor def _fetch_preconditioner(preconditioner, A): @@ -48,14 +47,15 @@ def _fetch_preconditioner(preconditioner, A): @pytest.mark.platform_x86_gpu_training @pytest.mark.platform_x86_cpu @pytest.mark.env_onecard -@pytest.mark.parametrize('dtype, tol', [(onp.float32, 1e-5), (onp.float64, 1e-12)]) -@pytest.mark.parametrize('shape', [(4, 4), (7, 7)]) +@pytest.mark.parametrize('tensor_type, dtype, tol', [('Tensor', onp.float32, 1e-5), ('Tensor', onp.float64, 1e-12), + ('CSRTensor', onp.float32, 1e-5)]) +@pytest.mark.parametrize('shape', [(7, 7)]) @pytest.mark.parametrize('preconditioner', [None, 'identity', 'exact', 'random']) -@pytest.mark.parametrize('maxiter', [1, 3]) -def test_cg_against_scipy(dtype, tol, shape, preconditioner, maxiter): +@pytest.mark.parametrize('maxiter', [3, None]) +def test_cg_against_scipy(tensor_type, dtype, tol, shape, preconditioner, maxiter): """ Feature: ALL TO ALL - Description: test cases for cg + Description: test cases for cg using function way in pynative/graph mode Expectation: the result match scipy """ onp.random.seed(0) @@ -64,9 +64,9 @@ def test_cg_against_scipy(dtype, tol, shape, preconditioner, maxiter): m = _fetch_preconditioner(preconditioner, a) osp_res = scipy.sparse.linalg.cg(a, b, M=m, maxiter=maxiter, atol=tol, tol=tol) - a = Tensor(a) + a = to_tensor((a, tensor_type)) b = Tensor(b) - m = Tensor(m) if m is not None else m + m = to_tensor((m, tensor_type)) if m is not None else m # using PYNATIVE MODE context.set_context(mode=context.PYNATIVE_MODE) @@ -117,17 +117,17 @@ def test_cg_against_numpy(dtype, shape): @pytest.mark.platform_x86_gpu_training @pytest.mark.platform_x86_cpu @pytest.mark.env_onecard -@pytest.mark.parametrize('dtype, tol', [(onp.float32, 1e-5), (onp.float64, 1e-12)]) +@pytest.mark.parametrize('tensor_type, dtype, tol', [('Tensor', onp.float32, 1e-5), ('Tensor', onp.float64, 1e-12), + ('CSRTensor', onp.float32, 1e-5)]) @pytest.mark.parametrize('shape', [(7, 7)]) @pytest.mark.parametrize('preconditioner', [None, 'identity', 'exact', 'random']) -@pytest.mark.parametrize('maxiter', [3]) -def test_cg_against_scipy_graph(dtype, tol, shape, preconditioner, maxiter): +@pytest.mark.parametrize('maxiter', [3, None]) +def test_cg_against_scipy_graph(tensor_type, dtype, tol, shape, preconditioner, maxiter): """ Feature: ALL TO ALL - Description: test cases for cg within Cell object + Description: test cases for cg within Cell object in pynative/graph mode Expectation: the result match scipy """ - context.set_context(mode=context.GRAPH_MODE) class Net(nn.Cell): def construct(self, a, b, m, maxiter, tol): @@ -139,52 +139,23 @@ def test_cg_against_scipy_graph(dtype, tol, shape, preconditioner, maxiter): m = _fetch_preconditioner(preconditioner, a) osp_res = scipy.sparse.linalg.cg(a, b, M=m, maxiter=maxiter, atol=tol, tol=tol) - a = Tensor(a) + a = to_tensor((a, tensor_type)) b = Tensor(b) - m = Tensor(m) if m is not None else m - msp_res = Net()(a, b, m, maxiter, tol) + m = to_tensor((m, tensor_type)) if m is not None else m - kw = {"atol": tol, "rtol": tol} - onp.testing.assert_allclose(osp_res[0], msp_res[0].asnumpy(), **kw) - assert osp_res[1] == msp_res[1].asnumpy().item() + # using PYNATIVE MODE + context.set_context(mode=context.PYNATIVE_MODE) + msp_res_dyn = Net()(a, b, m, maxiter, tol) - -@pytest.mark.level0 -@pytest.mark.platform_x86_gpu_training -@pytest.mark.env_onecard -@pytest.mark.parametrize('dtype, tol', [(onp.float32, 1e-5)]) -@pytest.mark.parametrize('shape', [(7, 7)]) -@pytest.mark.parametrize('preconditioner', [None, 'identity', 'random']) -@pytest.mark.parametrize('maxiter', [3]) -def test_cg_against_scipy_sparse(dtype, tol, shape, preconditioner, maxiter): - """ - Feature: ALL TO ALL - Description: test cases of CSRTensor for cg - Expectation: the result match scipy. - """ + # using GRAPH MODE context.set_context(mode=context.GRAPH_MODE) - - class Net(nn.Cell): - def construct(self, a, b, m, maxiter, tol): - return msp.sparse.linalg.cg(a, b, M=m, maxiter=maxiter, atol=tol, tol=tol) - - onp.random.seed(0) - - # scipy - a = create_sym_pos_sparse_matrix(shape, dtype) - b = onp.random.random(shape[:1]).astype(dtype) - m = _fetch_preconditioner(preconditioner, a) - osp_res = scipy.sparse.linalg.cg(a, b, M=m, maxiter=maxiter, atol=tol, tol=tol) - - # mindspore - a = CSRTensor(Tensor(a.indptr), Tensor(a.indices), Tensor(a.data), shape) - b = Tensor(b) - m = Tensor(m) if m is not None else m - msp_res = Net()(a, b, m, maxiter, tol) + msp_res_sta = Net()(a, b, m, maxiter, tol) kw = {"atol": tol, "rtol": tol} - onp.testing.assert_allclose(osp_res[0], msp_res[0].asnumpy(), **kw) - assert osp_res[1] == msp_res[1].asnumpy().item() + onp.testing.assert_allclose(osp_res[0], msp_res_dyn[0].asnumpy(), **kw) + onp.testing.assert_allclose(osp_res[0], msp_res_sta[0].asnumpy(), **kw) + assert osp_res[1] == msp_res_dyn[1].asnumpy().item() + assert osp_res[1] == msp_res_sta[1].asnumpy().item() @pytest.mark.level0 diff --git a/tests/st/scipy_st/utils.py b/tests/st/scipy_st/utils.py index 2b9f04b0f57..024d15819de 100644 --- a/tests/st/scipy_st/utils.py +++ b/tests/st/scipy_st/utils.py @@ -14,18 +14,17 @@ # ============================================================================ """utility functions for mindspore.scipy st tests""" from typing import List -from functools import cmp_to_key, partial +from functools import cmp_to_key import numpy as onp import scipy as osp -import scipy.sparse.linalg from mindspore import Tensor, CSRTensor import mindspore.ops as ops import mindspore.numpy as mnp from mindspore.common import dtype as mstype -def to_tensor(obj, dtype=None): +def to_tensor(obj, dtype=None, indice_dtype=onp.int32): """ This function is used to initialize Tensor or CSRTensor. 'obj' can be three type: @@ -45,13 +44,14 @@ def to_tensor(obj, dtype=None): dtype = obj.dtype if isinstance(obj, onp.ndarray): - tensor_fn = partial(Tensor, input_data=obj.astype(dtype)) - else: - tensor_fn = partial(CSRTensor, indptr=Tensor(obj.indptr), indices=Tensor(obj.indices), - values=Tensor(obj.data.astype(dtype)), shape=obj.shape) + obj = Tensor(obj.astype(dtype)) + elif isinstance(obj, osp.sparse.csr_matrix): + obj = CSRTensor(indptr=Tensor(obj.indptr.astype(indice_dtype)), + indices=Tensor(obj.indices.astype(indice_dtype)), + values=Tensor(obj.data.astype(dtype)), + shape=obj.shape) - res = tensor_fn() - return res + return obj def match_array(actual, expected, error=0, err_msg=''): @@ -117,18 +117,6 @@ def create_sym_pos_matrix(shape, dtype): return (onp.matmul(x, x.T) + onp.eye(n)).astype(dtype) -def create_sym_pos_sparse_matrix(shape, dtype, indice_dtype=onp.int32): - if len(shape) != 2 or shape[0] != shape[1]: - raise ValueError( - 'Symmetric positive definite matrix must be a square matrix, but has shape: ', shape) - - n = shape[-1] - indptr = onp.arange(n + 1).astype(indice_dtype) - indices = onp.arange(n).astype(indice_dtype) - values = onp.random.random(n).astype(dtype) - return scipy.sparse.csr_matrix((values, indices, indptr), shape=shape) - - def gradient_check(x, net, epsilon=1e-3, symmetric=False, enumerate_fn=onp.ndenumerate): # Some utils def _tensor_to_numpy(arg: List[Tensor]) -> List[onp.ndarray]: