diff --git a/docs/api/api_python/mindspore/mindspore.CSRTensor.rst b/docs/api/api_python/mindspore/mindspore.CSRTensor.rst index 6f0e2aff754..1a20cfb73d7 100644 --- a/docs/api/api_python/mindspore/mindspore.CSRTensor.rst +++ b/docs/api/api_python/mindspore/mindspore.CSRTensor.rst @@ -15,7 +15,7 @@ mindspore.CSRTensor - **indptr** (Tensor) - 形状为 `[M]` 的一维整数张量,其中M等于 `shape[0] + 1` , 表示每行非零元素的在 `values` 中存储的起止位置。默认值:None。支持的数据类型为 `int16` , `int32` 和 `int64` 。 - **indices** (Tensor) - 形状为 `[N]` 的一维整数张量,其中N等于非零元素数量,表示每个元素的列索引值。默认值:None。支持的数据类型为 `int16` , `int32` 和 `int64` 。 - **values** (Tensor) - 形状为 `[N]` 的一维张量,用来表示索引对应的数值。默认值:None。 - - **shape** (tuple(int)) - 形状为ndims的整数元组,用来指定稀疏矩阵的稠密形状。目前只支持2维CSRTensor,所以 `shape` 长度只能为2。`shape[0]` 表示行数,因此必须和 `indptr[0] - 1` 值相等。默认值:None。 + - **shape** (tuple(int)) - 形状为ndims的整数元组,用来指定稀疏矩阵的稠密形状。目前只支持2维CSRTensor,所以 `shape` 长度只能为2。`shape[0]` 表示行数,因此必须和 `M - 1` 值相等。默认值:None。 - **csr_tensor** (CSRTensor) - CSRTensor对象,用来初始化新的CSRTensor。默认值:None。 **输出:** @@ -69,7 +69,7 @@ mindspore.CSRTensor **参数:** - - **dense_vector** (Tensor) - 形状为 `[N,1]` 的一维张量,其中N等于CSRTensor的列数。 + - **dense_vector** (Tensor) - 形状为 `[N,1]` 的二维张量,其中N等于CSRTensor的列数。 **返回:** diff --git a/mindspore/core/abstract/prim_others.cc b/mindspore/core/abstract/prim_others.cc index 8c54c077b9c..0489e23a2bb 100644 --- a/mindspore/core/abstract/prim_others.cc +++ b/mindspore/core/abstract/prim_others.cc @@ -60,6 +60,19 @@ inline void CheckSparseShape(ShapeVector sparse_shp, ShapeVector dense_shp) { } } } +inline void CheckSparseShape(const size_t shape_size, const size_t expected_dim, const std::string &arg_name) { + if (shape_size != expected_dim) { + MS_EXCEPTION(mindspore::ValueError) << arg_name << " must be a " << expected_dim + << "-dimensional tensor, but got a " << shape_size << "-dimensional tensor."; + } +} +inline void CheckSparseIndicesDtype(const mindspore::TypePtr data_type, const std::string &arg_name) { + if (!(data_type->equal(mindspore::kInt16) || data_type->equal(mindspore::kInt32) || + data_type->equal(mindspore::kInt64))) { + MS_EXCEPTION(mindspore::TypeError) << "The dtype of " << arg_name << " must be Int16 or Int32 or Int64, but got " + << data_type->ToString() << "."; + } +} } // namespace namespace mindspore { @@ -370,19 +383,14 @@ AbstractBasePtr InferImplMakeCOOTensor(const AnalysisEnginePtr &, const Primitiv auto dense_shape = CheckArg(op_name, args_spec_list, kIndexTwo); auto indices_dtype = indices->element()->BuildType(); - if (!indices_dtype->isa()) { - MS_EXCEPTION(TypeError) << "The dtype of indices must be a Int, but got " << indices_dtype->ToString(); - } + CheckSparseIndicesDtype(indices_dtype, "indices"); + auto indices_shp = indices->shape()->shape(); - if (indices_shp.size() != kSizeTwo) { - MS_EXCEPTION(TypeError) << "Indices must be a 2 dimensional tensor, but got a " << indices_shp.size() - << " dimension tensor"; - } + CheckSparseShape(indices_shp.size(), kSizeTwo, "Indices"); + auto values_shp = values->shape()->shape(); - if (values_shp.size() != kSizeOne) { - MS_EXCEPTION(TypeError) << "Values must be a 1 dimensional tensor, but got a " << values_shp.size() - << " dimension tensor"; - } + CheckSparseShape(values_shp.size(), kSizeOne, "Values"); + if (indices_shp[kIndexZero] != values_shp[kIndexZero]) { MS_EXCEPTION(TypeError) << "Indices and values must equal in their shape, but got indices shape: " << indices_shp[0] << ", values shape: " << values_shp[kIndexZero]; @@ -505,14 +513,19 @@ AbstractBasePtr InferImplCSRMV(const AnalysisEnginePtr &, const PrimitivePtr &pr << "but sparse tensor has " << sparse_shape.size() << " dimensions, " << "and dense tensor has " << dense_shape.size() << " dimensions, "; } + if (dense_shape[kIndexZero] != sparse_shape[kIndexOne] || dense_shape[kIndexOne] != 1) { + MS_EXCEPTION(ValueError) << "The dense_vector's shape should be (" << sparse_shape[kIndexOne] << ", 1)" + << ", but its current shape is: " + << "(" << dense_shape[kIndexZero] << ", " << dense_shape[kIndexOne] << ")."; + } MS_EXCEPTION_IF_NULL(sparse->values()->element()); - ShapeVector out_shape = {sparse_shape[0], dense_shape[1]}; + ShapeVector out_shape = {sparse_shape[kIndexZero], dense_shape[kIndexOne]}; auto ret = std::make_shared(sparse->values()->element()->BuildType(), out_shape); MS_EXCEPTION_IF_NULL(sparse->indices()->shape()); auto nnz_vec = sparse->indices()->shape()->shape(); - auto csr_avg_rows = nnz_vec[0] / dense_shape[0]; + auto csr_avg_rows = nnz_vec[kIndexZero] / dense_shape[kIndexZero]; primitive->set_attr(kCSRAvgRows, MakeValue(csr_avg_rows)); primitive->set_attr(kCSRDenseShape, MakeValue(sparse_shape)); primitive->set_attr(kIsCSR, MakeValue(true)); @@ -668,34 +681,25 @@ AbstractBasePtr InferImplMakeCSRTensor(const AnalysisEnginePtr &, const Primitiv auto values = CheckArg(op_name, args_spec_list, kIndexTwo); auto shape = CheckArg(op_name, args_spec_list, kIndexThree); + auto indptr_dtype = indptr->element()->BuildType(); auto indices_dtype = indices->element()->BuildType(); - if (!indices_dtype->isa()) { - MS_EXCEPTION(TypeError) << "The dtype of indices must be a Int, but got " << indices_dtype->ToString(); - } + CheckSparseIndicesDtype(indptr_dtype, "indptr"); + CheckSparseIndicesDtype(indices_dtype, "indices"); + auto indptr_shp = indptr->shape()->shape(); - if (indptr_shp.size() != 1) { - MS_EXCEPTION(ValueError) << "Indptr must be a 1-dimensional tensor, but got a " << indptr_shp.size() - << "-dimensional tensor"; - } + CheckSparseShape(indptr_shp.size(), kSizeOne, "Indptr"); + auto indices_shp = indices->shape()->shape(); - if (indices_shp.size() != 1) { - MS_EXCEPTION(ValueError) << "Indices must be a 1-dimensional tensor, but got a " << indices_shp.size() - << "-dimensional tensor"; - } + CheckSparseShape(indices_shp.size(), kSizeOne, "Indices"); + auto values_shp = values->shape()->shape(); - if (values_shp.size() != 1) { - MS_EXCEPTION(ValueError) << "Values must be a 1-dimensional tensor, but got a " << values_shp.size() - << "-dimensional tensor"; - } - if (indices_shp[0] != values_shp[0]) { - MS_EXCEPTION(ValueError) << "Indices and values must have same size, but got: values length: " << values_shp[0] - << ", indices length " << indices_shp[0]; - } - for (const auto &elem_type : shape->ElementsType()) { - if (!elem_type->isa()) { - MS_EXCEPTION(TypeError) << "The element type of shape must be Int, but got " << elem_type->ToString(); - } + CheckSparseShape(values_shp.size(), kSizeOne, "Values"); + + if (indices_shp[kIndexZero] != values_shp[kIndexZero]) { + MS_EXCEPTION(ValueError) << "Indices and values must have same size, but got: values length: " + << values_shp[kIndexZero] << ", indices length " << indices_shp[kIndexZero]; } + auto shape_value = shape->BuildValue()->cast(); MS_EXCEPTION_IF_NULL(shape_value); auto shp = shape_value->value(); @@ -704,19 +708,33 @@ AbstractBasePtr InferImplMakeCSRTensor(const AnalysisEnginePtr &, const Primitiv auto elem = GetValue(e); return elem; }); + if (shape_vec.size() != kSizeTwo) { + MS_EXCEPTION(ValueError) << "Currently only supports 2-dimensional csr tensor, got shape length = " + << shape_vec.size() << "."; + } if (values_shp.size() + 1 != shape_vec.size()) { MS_EXCEPTION(ValueError) << "Values' dimension should equal to csr_tensor's dimension - 1."; } - if (shape_vec[0] + 1 != indptr_shp[0]) { - MS_EXCEPTION(ValueError) << "Indptr must have length (1 + shape[0]), but got: " << indptr_shp[0]; + if (shape_vec[kIndexZero] + 1 != indptr_shp[kIndexZero]) { + MS_EXCEPTION(ValueError) << "Indptr must have length (1 + shape[0]), but got: " << indptr_shp[kIndexZero]; } + size_t shape_size = 1; + auto shape_types = shape->ElementsType(); for (size_t i = 0; i < shape_vec.size(); ++i) { if (shape_vec[i] <= 0) { - MS_EXCEPTION(TypeError) << "The element of shape must be positive, but got " << shape_value->ToString(); + MS_EXCEPTION(ValueError) << "The element of shape must be positive, but got " << shape_value->ToString(); } if ((i > 1) && (shape_vec[i] != values_shp[i - 1])) { MS_EXCEPTION(ValueError) << "csr_tensor's shape should match with values' shape."; } + if (!shape_types[i]->isa()) { + MS_EXCEPTION(TypeError) << "The element type of shape must be Int, but got " << shape_types[i]->ToString(); + } + shape_size *= shape_vec[i]; + } + if (static_cast(shape_size) < values_shp[kIndexZero]) { + MS_EXCEPTION(ValueError) << "Shape total size: " << shape_size << " is too small to hold " << values_shp[kIndexZero] + << " non-zero values."; } auto ret = std::make_shared(values->element()->BuildType(), shape_vec); ret->set_indptr(indptr); diff --git a/mindspore/python/mindspore/_checkparam.py b/mindspore/python/mindspore/_checkparam.py index b219d33c653..493f58f896d 100644 --- a/mindspore/python/mindspore/_checkparam.py +++ b/mindspore/python/mindspore/_checkparam.py @@ -873,19 +873,23 @@ class Validator: def check_csr_tensor_input(indptr, indices, values, shape): """Checks inputs type for CSRTensor.""" if not isinstance(indptr, Tensor_): - raise TypeError(f"indptr should be Tensor, but got {type(indices)}.") + raise TypeError(f"indptr should be Tensor, but got {type(indptr)}.") Validator.check_sparse_tensor_input(indices, values, shape) @staticmethod def check_csr_tensor_shape(indptr_shp, indices_shp, values_shp, csr_shp): """Checks input tensors' shapes for CSRTensor.""" if len(csr_shp) != 2: - raise ValueError("Currently only supports 2-dimensional csr tensor.") + raise ValueError(f"Currently only supports 2-dimensional csr tensor, got `shape length`={len(csr_shp)}.") + shape_size = 1 for item in csr_shp: if item <= 0: raise ValueError(f"The element of shape must be positive, but got {item}") if not isinstance(item, int): raise TypeError(f"The element type of shape must be int, but got {type(item)}") + shape_size *= item + if shape_size < values_shp[0]: + raise ValueError(f"Shape total size: {shape_size} is too small to hold {values_shp[0]} non-zero values.") if len(values_shp) != 1: raise ValueError(f"Values must be a 1-dimensional tensor, but got a {len(values_shp)} dimension tensor.") if len(indices_shp) != 1: @@ -903,9 +907,9 @@ class Validator: def check_csr_tensor_dtype(indptr_dtype, indices_dtype): """Checks input tensors' data types for CSRTensor.""" if indptr_dtype not in (mstype.int16, mstype.int32, mstype.int64): - raise TypeError("Indptr must have integer data type.") + raise TypeError(f"Indptr must have int16 or int32 or int64 data type, but got {indptr_dtype}.") if indices_dtype not in (mstype.int16, mstype.int32, mstype.int64): - raise TypeError("Indices must have integer data type.") + raise TypeError(f"Indices must have int16 or int32 or int64 data type, but got {indices_dtype}.") @staticmethod def check_coo_tensor_input(indices, values, shape): @@ -937,7 +941,7 @@ class Validator: def check_coo_tensor_dtype(indices_dtype): """Checks input tensors' data types for COOTensor.""" if indices_dtype not in (mstype.int16, mstype.int32, mstype.int64): - raise TypeError("Indices must have integer data type.") + raise TypeError(f"Indices must have int16 or int32 or int64 data type, but got {indices_dtype}.") def check_input_format(input_param): diff --git a/mindspore/python/mindspore/_extends/parse/standard_method.py b/mindspore/python/mindspore/_extends/parse/standard_method.py index 675c0282d0e..ebc5aef577b 100644 --- a/mindspore/python/mindspore/_extends/parse/standard_method.py +++ b/mindspore/python/mindspore/_extends/parse/standard_method.py @@ -1929,6 +1929,7 @@ def csr_abs(x): def csr_mv(x, dense_vector): """Implementation of `abs` for CSRTensor.""" + check_value_type('dense_vector', dense_vector, (Tensor_,), 'Tensor') return F.csr_mv(x, dense_vector) diff --git a/mindspore/python/mindspore/common/tensor.py b/mindspore/python/mindspore/common/tensor.py index 488040e52d5..0ee8fdbc0c1 100644 --- a/mindspore/python/mindspore/common/tensor.py +++ b/mindspore/python/mindspore/common/tensor.py @@ -2631,17 +2631,17 @@ class CSRTensor(CSRTensor_): If the length of values or indices exceeds the range indicated by indptr, its behavior will be undefined. Args: - indptr (Tensor): 1-D Tensor of size `shape[0] + 1`, which indicates the + indptr (Tensor): 1-D Tensor of shape `[M]`, which equals to `shape[0] + 1`, which indicates the start and end point for `values` in each row. Default: None. If provided, must be :class:`mindspore.int16`, :class:`mindspore.int32` or :class:`mindspore.int64`. - indices (Tensor): 1-D Tensor, which has the same length as `values`. `indices` + indices (Tensor): 1-D Tensor of shape `[N]`, which has the same length as `values`. `indices` indicates the which column `values` should be placed. Default: None. If provided, must be :class:`mindspore.int16`, :class:`mindspore.int32` or :class:`mindspore.int64`. - values (Tensor): 1-D Tensor, which has the same length as `indices`. `values` + values (Tensor): 1-D Tensor of shape `[N]`, which has the same length as `indices`. `values` stores the data for CSRTensor. Default: None. shape (Tuple): A tuple indicates the shape of the CSRTensor, its length must be `2`, as only 2-D CSRTensor is currently supported, and `shape[0]` must - equal to `indptr[0] - 1`, which all equal to number of rows of the CSRTensor. Default: None. + equal to `M - 1`, which all equal to number of rows of the CSRTensor. Default: None. csr_tensor (CSRTensor): A CSRTensor object. Default: None. Outputs: @@ -2808,7 +2808,7 @@ class CSRTensor(CSRTensor_): Sparse matrix-vector multiplication. Args: - dense_vector (Tensor) - A dense Tensor. + dense_vector (Tensor) - A dense Tensor, its shape must be (csr_tensor.shape[1], 1) Returns: Tensor. @@ -2829,6 +2829,7 @@ class CSRTensor(CSRTensor_): [[2.] [1.]] """ + validator.check_value_type('dense_vector', dense_vector, (Tensor_,), 'Tensor') return tensor_operator_registry.get("csr_mv")(self, dense_vector) def sum(self, axis):