From 9dfc703f7ace8bcb954f26dbd594f9d9ba8092d7 Mon Sep 17 00:00:00 2001 From: wangrao124 Date: Thu, 23 Dec 2021 19:11:33 +0800 Subject: [PATCH] change sparsetensor to cootensor --- .../mindspore/mindspore.SparseTensor.rst | 8 +- .../cpu/nnacl/infer/common_infer.h | 2 +- .../backend/optimizer/pass/sparse_process.cc | 20 ++- .../backend/session/anf_runtime_algorithm.cc | 2 +- mindspore/ccsrc/debug/dump_proto.cc | 2 +- mindspore/ccsrc/debug/tensor_data.h | 2 +- mindspore/ccsrc/frontend/optimizer/clean.cc | 18 +-- mindspore/ccsrc/frontend/optimizer/irpass.cc | 2 +- .../irpass/sparse_tensor_eliminate.h | 8 +- mindspore/ccsrc/pipeline/jit/resource.cc | 8 +- .../pipeline/jit/static_analysis/prim.cc | 4 +- mindspore/ccsrc/pipeline/jit/validator.cc | 4 +- mindspore/ccsrc/pybind_api/ir/dtype_py.cc | 4 +- mindspore/ccsrc/pybind_api/ir/tensor_py.cc | 58 ++++++-- mindspore/ccsrc/pybind_api/ir/tensor_py.h | 6 + mindspore/ccsrc/utils/convert_utils.h | 14 +- mindspore/ccsrc/utils/convert_utils_py.cc | 72 +++++++--- mindspore/ccsrc/vm/backend.cc | 2 +- mindspore/core/abstract/abstract_value.cc | 20 +-- mindspore/core/abstract/abstract_value.h | 30 ++--- mindspore/core/abstract/infer_functions.h | 14 +- mindspore/core/abstract/param_validator.h | 2 +- mindspore/core/abstract/prim_others.cc | 24 ++-- .../core/abstract/primitive_infer_map.cc | 10 +- mindspore/core/base/core_ops.h | 21 ++- mindspore/core/ir/dtype/tensor_type.cc | 28 ++-- mindspore/core/ir/dtype/tensor_type.h | 30 ++--- mindspore/core/ir/dtype/type.cc | 2 +- mindspore/core/ir/dtype_extends.cc | 12 +- mindspore/core/ir/tensor.cc | 34 +++++ mindspore/core/ir/tensor.h | 51 +++++++ mindspore/core/mindapi/base/type_id.h | 2 +- .../include/ir/dtype/type_id.h | 2 +- .../mindspore/_extends/parse/resources.py | 3 +- mindspore/python/mindspore/common/__init__.py | 4 +- mindspore/python/mindspore/common/api.py | 5 +- mindspore/python/mindspore/common/dtype.py | 2 +- mindspore/python/mindspore/common/tensor.py | 125 ++++++++++++++---- .../python/mindspore/nn/sparse/sparse.py | 25 ++-- .../python/mindspore/ops/_grad/grad_sparse.py | 26 ++-- .../composite/multitype_ops/ones_like_impl.py | 8 +- mindspore/python/mindspore/ops/functional.py | 15 ++- tests/st/sparse/test_coo.py | 93 +++++++++++++ tests/st/sparse/test_csr.py | 4 +- .../gtest_input/optimizer/opt_test.py | 8 +- tests/ut/python/ir/test_sparse_tensor.py | 37 +++++- .../pynative_mode/test_sparse_pynative.py | 16 ++- 47 files changed, 640 insertions(+), 249 deletions(-) create mode 100644 tests/st/sparse/test_coo.py diff --git a/docs/api/api_python/mindspore/mindspore.SparseTensor.rst b/docs/api/api_python/mindspore/mindspore.SparseTensor.rst index 766d621c9c49..dcb61ec10906 100644 --- a/docs/api/api_python/mindspore/mindspore.SparseTensor.rst +++ b/docs/api/api_python/mindspore/mindspore.SparseTensor.rst @@ -1,7 +1,7 @@ mindspore.SparseTensor ====================== -.. py:class:: mindspore.SparseTensor(indices, values, dense_shape) +.. py:class:: mindspore.SparseTensor(indices, values, shape) 用来表示某一张量在给定索引上非零元素的集合。 @@ -10,14 +10,14 @@ mindspore.SparseTensor .. note:: 目前不支持PyNative模式。 - 对于稠密张量,其 `SparseTensor(indices, values, dense_shape)` 具有 `dense[indices[i]] = values[i]` 。 + 对于稠密张量,其 `SparseTensor(indices, values, shape)` 具有 `dense[indices[i]] = values[i]` 。 **参数:** - **indices** (Tensor) - 形状为 `[N, ndims]` 的二维整数张量,其中N和ndims分别表示稀疏张量中 `values` 的数量和SparseTensor维度的数量。 - **values** (Tensor) - 形状为[N]的一维张量,其内部可以为任何数据类型,用来给 `indices` 中的每个元素提供数值。 - - **dense_shape** (tuple(int)) - 形状为ndims的整数元组,用来指定稀疏矩阵的稠密形状。 + - **shape** (tuple(int)) - 形状为ndims的整数元组,用来指定稀疏矩阵的稠密形状。 **返回:** - SparseTensor,由 `indices` 、 `values` 和 `dense_shape` 组成。 + SparseTensor,由 `indices` 、 `values` 和 `shape` 组成。 diff --git a/mindspore/ccsrc/backend/kernel_compiler/cpu/nnacl/infer/common_infer.h b/mindspore/ccsrc/backend/kernel_compiler/cpu/nnacl/infer/common_infer.h index 4abf3f7365eb..3d62b8f7fb2b 100644 --- a/mindspore/ccsrc/backend/kernel_compiler/cpu/nnacl/infer/common_infer.h +++ b/mindspore/ccsrc/backend/kernel_compiler/cpu/nnacl/infer/common_infer.h @@ -79,7 +79,7 @@ typedef enum TypeIdC { kObjectTypeKeyword, kObjectTypeTensorType, kObjectTypeRowTensorType, - kObjectTypeSparseTensorType, + kObjectTypeCOOTensorType, kObjectTypeUndeterminedType, kObjectTypeClass, kObjectTypeDictionary, diff --git a/mindspore/ccsrc/backend/optimizer/pass/sparse_process.cc b/mindspore/ccsrc/backend/optimizer/pass/sparse_process.cc index 74b4f546dcde..3ed0cd74b13b 100644 --- a/mindspore/ccsrc/backend/optimizer/pass/sparse_process.cc +++ b/mindspore/ccsrc/backend/optimizer/pass/sparse_process.cc @@ -117,6 +117,20 @@ bool SplitCNode(const AnfNodePtr &node, std::vector *new_inputs) { return true; } +std::vector GetAbstractList(const AnfNodePtr &node, const std::string &prim_name) { + MS_EXCEPTION_IF_NULL(node); + if (prim_name == prim::kPrimMakeCSRTensor->name()) { + auto abs_sparse = dyn_cast(node->abstract()); + MS_EXCEPTION_IF_NULL(abs_sparse); + return {abs_sparse->indptr(), abs_sparse->indices(), abs_sparse->values(), abs_sparse->dense_shape()}; + } else if (prim_name == prim::kPrimMakeCOOTensor->name()) { + auto abs_sparse = dyn_cast(node->abstract()); + MS_EXCEPTION_IF_NULL(abs_sparse); + return {abs_sparse->indices(), abs_sparse->values(), abs_sparse->dense_shape()}; + } + return {}; +} + const AnfNodePtr SparseProcess::Process(const FuncGraphPtr &func_graph, const AnfNodePtr &node, const EquivPtr &) const { MS_EXCEPTION_IF_NULL(func_graph); @@ -134,13 +148,9 @@ const AnfNodePtr SparseProcess::Process(const FuncGraphPtr &func_graph, const An if (make_sparse_set.find(prim_name) != make_sparse_set.end()) { std::vector inputs; inputs.emplace_back(NewValueNode(prim::kPrimMakeTuple)); - // Inputs of node should be [make_sparse, indices, values, dense_shape], so offset by 1 to get items; (void)inputs.insert(inputs.end(), cnode->inputs().begin() + 1, cnode->inputs().end()); auto new_node = cnode->func_graph()->NewCNode(inputs); - auto abs_sparse = dyn_cast(node->abstract()); - MS_EXCEPTION_IF_NULL(abs_sparse); - std::vector abstract_list{abs_sparse->indptr(), abs_sparse->indices(), abs_sparse->values(), - abs_sparse->dense_shape()}; + std::vector abstract_list = GetAbstractList(node, prim_name); auto abs_res = std::make_shared(abstract_list); new_node->set_abstract(abs_res); new_node->set_scope(cnode->scope()); diff --git a/mindspore/ccsrc/backend/session/anf_runtime_algorithm.cc b/mindspore/ccsrc/backend/session/anf_runtime_algorithm.cc index 8ad954f0b2bf..5e7d9bfd0eb4 100644 --- a/mindspore/ccsrc/backend/session/anf_runtime_algorithm.cc +++ b/mindspore/ccsrc/backend/session/anf_runtime_algorithm.cc @@ -159,7 +159,7 @@ std::vector GetAllOutputWithIndexInner(const AnfNodePtr &node) const PrimitiveSet expand_prims{ prim::kPrimMakeTuple, prim::kPrimMakeCSRTensor, - prim::kPrimMakeSparseTensor, + prim::kPrimMakeCOOTensor, prim::kPrimMakeRowTensor, }; // The MakeTuple/MakeSparse node need expand and recurse. diff --git a/mindspore/ccsrc/debug/dump_proto.cc b/mindspore/ccsrc/debug/dump_proto.cc index 79a624844d32..5e63e2c4aada 100644 --- a/mindspore/ccsrc/debug/dump_proto.cc +++ b/mindspore/ccsrc/debug/dump_proto.cc @@ -119,7 +119,7 @@ void CheckIfValidType(const TypePtr &type) { if (!(type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || type->isa() || - type->isa() || type->isa() || type->isa() || + type->isa() || type->isa() || type->isa() || type->isa() || type->isa())) { MS_LOG(EXCEPTION) << "Unknown type: " << type->type_name(); } diff --git a/mindspore/ccsrc/debug/tensor_data.h b/mindspore/ccsrc/debug/tensor_data.h index 46e4a1190e75..5b4aab7e10f3 100644 --- a/mindspore/ccsrc/debug/tensor_data.h +++ b/mindspore/ccsrc/debug/tensor_data.h @@ -56,7 +56,7 @@ typedef enum MsTypeId : unsigned int { kObjectTypeKeyword, kObjectTypeTensorType, kObjectTypeRowTensorType, - kObjectTypeSparseTensorType, + kObjectTypeCOOTensorType, kObjectTypeUndeterminedType, kObjectTypeClass, kObjectTypeDictionary, diff --git a/mindspore/ccsrc/frontend/optimizer/clean.cc b/mindspore/ccsrc/frontend/optimizer/clean.cc index f2c6165dac33..bc464f0dd018 100644 --- a/mindspore/ccsrc/frontend/optimizer/clean.cc +++ b/mindspore/ccsrc/frontend/optimizer/clean.cc @@ -29,12 +29,12 @@ namespace mindspore { namespace opt { using mindspore::abstract::AbstractAttribute; using mindspore::abstract::AbstractClass; +using mindspore::abstract::AbstractCOOTensor; using mindspore::abstract::AbstractDictionary; using mindspore::abstract::AbstractJTagged; using mindspore::abstract::AbstractList; using mindspore::abstract::AbstractRowTensor; using mindspore::abstract::AbstractScalar; -using mindspore::abstract::AbstractSparseTensor; using mindspore::abstract::AbstractTuple; using mindspore::abstract::AbstractUndetermined; @@ -79,8 +79,8 @@ static AbstractBasePtr AdaptAbs(const AbstractBasePtr &t) { return std::make_shared(abs_list->elements()); } - if (t->isa()) { - auto abs_sparse = dyn_cast(t); + if (t->isa()) { + auto abs_sparse = dyn_cast(t); std::vector abstract_list{abs_sparse->indices(), abs_sparse->values(), abs_sparse->dense_shape()}; return std::make_shared(abstract_list); } @@ -511,19 +511,15 @@ bool CleanAfterOptA(const FuncGraphPtr &root, const FuncGraphManagerPtr &manager new_node = ConvertListSetItemToTupleSetItem(cnode); } else if (IsValueNode(node)) { new_node = ConvertValueListNodeToValueTupleNode(node->cast()); - } else if (IsPrimitiveCNode(node, prim::kPrimMakeSparseTensor) || - IsPrimitiveCNode(node, prim::kPrimMakeRowTensor)) { + } else if (IsPrimitiveCNode(node, prim::kPrimMakeRowTensor)) { new_node = ConvertMakeSparseToMakeTuple(cnode); - } else if (IsPrimitiveCNode(node, prim::kPrimSparseTensorGetIndices) || - IsPrimitiveCNode(node, prim::kPrimRowTensorGetIndices)) { + } else if (IsPrimitiveCNode(node, prim::kPrimRowTensorGetIndices)) { constexpr int64_t indices_index = 0; new_node = ConvertSparseGetAttrToTupleGetItem(cnode, indices_index); - } else if (IsPrimitiveCNode(node, prim::kPrimSparseTensorGetValues) || - IsPrimitiveCNode(node, prim::kPrimRowTensorGetValues)) { + } else if (IsPrimitiveCNode(node, prim::kPrimRowTensorGetValues)) { constexpr int64_t value_index = 1; new_node = ConvertSparseGetAttrToTupleGetItem(cnode, value_index); - } else if (IsPrimitiveCNode(node, prim::kPrimSparseTensorGetDenseShape) || - IsPrimitiveCNode(node, prim::kPrimRowTensorGetDenseShape)) { + } else if (IsPrimitiveCNode(node, prim::kPrimRowTensorGetDenseShape)) { constexpr int64_t shape_index = 2; new_node = ConvertSparseGetAttrToTupleGetItem(cnode, shape_index); } diff --git a/mindspore/ccsrc/frontend/optimizer/irpass.cc b/mindspore/ccsrc/frontend/optimizer/irpass.cc index 4062873e0ba7..36a1781ada26 100644 --- a/mindspore/ccsrc/frontend/optimizer/irpass.cc +++ b/mindspore/ccsrc/frontend/optimizer/irpass.cc @@ -249,7 +249,7 @@ OptimizeIRPassLib::OptimizeIRPassLib() { // SparseTensor Eliminate sparse_tensor_eliminate_ = MakeSubstitution( std::make_shared(), "sparse_tensor_eliminate", - {prim::kPrimSparseTensorGetIndices, prim::kPrimSparseTensorGetValues, prim::kPrimSparseTensorGetDenseShape}); + {prim::kPrimCOOTensorGetIndices, prim::kPrimCOOTensorGetValues, prim::kPrimCOOTensorGetDenseShape}); // Value_Based Eliminate value_based_eliminate_ = MakeSubstitution(std::make_shared(), "value_based_eliminate", diff --git a/mindspore/ccsrc/frontend/optimizer/irpass/sparse_tensor_eliminate.h b/mindspore/ccsrc/frontend/optimizer/irpass/sparse_tensor_eliminate.h index c0a7bb5cf70a..94c2dc6717a8 100644 --- a/mindspore/ccsrc/frontend/optimizer/irpass/sparse_tensor_eliminate.h +++ b/mindspore/ccsrc/frontend/optimizer/irpass/sparse_tensor_eliminate.h @@ -35,10 +35,10 @@ class SparseTensorEliminater : public OptimizerCaller { public: AnfNodePtr operator()(const OptimizerPtr &, const AnfNodePtr &node) override { PatternNode x, y, z; - auto sparse = PPrimitive(prim::kPrimMakeSparseTensor, x, y, z).MinExtraNodes(0); - MATCH_REPLACE(node, PPrimitive(prim::kPrimSparseTensorGetIndices, sparse), x); - MATCH_REPLACE(node, PPrimitive(prim::kPrimSparseTensorGetValues, sparse), y); - MATCH_REPLACE(node, PPrimitive(prim::kPrimSparseTensorGetDenseShape, sparse), z); + auto sparse = PPrimitive(prim::kPrimMakeCOOTensor, x, y, z).MinExtraNodes(0); + MATCH_REPLACE(node, PPrimitive(prim::kPrimCOOTensorGetIndices, sparse), x); + MATCH_REPLACE(node, PPrimitive(prim::kPrimCOOTensorGetValues, sparse), y); + MATCH_REPLACE(node, PPrimitive(prim::kPrimCOOTensorGetDenseShape, sparse), z); return nullptr; } }; diff --git a/mindspore/ccsrc/pipeline/jit/resource.cc b/mindspore/ccsrc/pipeline/jit/resource.cc index 022ed9acbe7d..8c6a3af4e149 100644 --- a/mindspore/ccsrc/pipeline/jit/resource.cc +++ b/mindspore/ccsrc/pipeline/jit/resource.cc @@ -239,11 +239,11 @@ BuiltInTypeMap &GetAttrMap() { {"indices", prim::kPrimRowTensorGetIndices}, // F.row_tensor_get_indices {"dense_shape", prim::kPrimRowTensorGetDenseShape}, // F.row_tensor_get_dense_shape }}, - {kObjectTypeSparseTensorType, + {kObjectTypeCOOTensorType, { - {"values", prim::kPrimSparseTensorGetValues}, // F.sparse_tensor_get_values - {"indices", prim::kPrimSparseTensorGetIndices}, // F.sparse_tensor_get_indices - {"dense_shape", prim::kPrimSparseTensorGetDenseShape}, // F.sparse_tensor_get_dense_shape + {"values", prim::kPrimCOOTensorGetValues}, // F.coo_tensor_get_values + {"indices", prim::kPrimCOOTensorGetIndices}, // F.coo_tensor_get_indices + {"shape", prim::kPrimCOOTensorGetDenseShape}, // F.coo_tensor_get_dense_shape }}, {kObjectTypeCSRTensorType, { diff --git a/mindspore/ccsrc/pipeline/jit/static_analysis/prim.cc b/mindspore/ccsrc/pipeline/jit/static_analysis/prim.cc index 3ee57c1644fe..349c4145a035 100644 --- a/mindspore/ccsrc/pipeline/jit/static_analysis/prim.cc +++ b/mindspore/ccsrc/pipeline/jit/static_analysis/prim.cc @@ -557,8 +557,8 @@ py::dict ConvertAbstractToPython(const AbstractBasePtr &abs_base, bool only_conv dic[ATTR_SHAPE] = arg->shape()->shape(); dic[ATTR_DTYPE] = arg->BuildType(); dic[ATTR_VALUE] = BuildValue(arg->BuildValue()); - } else if (abs_base->isa()) { - auto arg = dyn_cast(abs_base); + } else if (abs_base->isa()) { + auto arg = dyn_cast(abs_base); dic[ATTR_SHAPE] = arg->shape()->shape(); dic[ATTR_DTYPE] = arg->BuildType(); dic[ATTR_VALUE] = BuildValue(arg->BuildValue()); diff --git a/mindspore/ccsrc/pipeline/jit/validator.cc b/mindspore/ccsrc/pipeline/jit/validator.cc index 6d15a0dec734..8f5b81e4074c 100644 --- a/mindspore/ccsrc/pipeline/jit/validator.cc +++ b/mindspore/ccsrc/pipeline/jit/validator.cc @@ -31,6 +31,7 @@ namespace mindspore { namespace validator { using mindspore::abstract::AbstractBase; using mindspore::abstract::AbstractClass; +using mindspore::abstract::AbstractCOOTensor; using mindspore::abstract::AbstractCSRTensor; using mindspore::abstract::AbstractError; using mindspore::abstract::AbstractFunction; @@ -39,7 +40,6 @@ using mindspore::abstract::AbstractList; using mindspore::abstract::AbstractRef; using mindspore::abstract::AbstractRowTensor; using mindspore::abstract::AbstractScalar; -using mindspore::abstract::AbstractSparseTensor; using mindspore::abstract::AbstractTensor; using mindspore::abstract::AbstractTuple; using mindspore::abstract::AbstractType; @@ -122,7 +122,7 @@ void ValidateAbstract(const AnfNodePtr &node) { bool is_legal_abstract = abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa() || - abstract->isa() || abstract->isa() || + abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa() || abstract->isa(); if (is_legal_abstract) { diff --git a/mindspore/ccsrc/pybind_api/ir/dtype_py.cc b/mindspore/ccsrc/pybind_api/ir/dtype_py.cc index 256fcae0ff0b..dadd75c9c6e1 100644 --- a/mindspore/ccsrc/pybind_api/ir/dtype_py.cc +++ b/mindspore/ccsrc/pybind_api/ir/dtype_py.cc @@ -154,9 +154,9 @@ REGISTER_PYBIND_DEFINE( (void)py::class_>(m_sub, "RowTensorType") .def(py::init()) .def_property_readonly("ElementType", &RowTensorType::element, "Get the RowTensorType's element type."); - (void)py::class_>(m_sub, "SparseTensorType") + (void)py::class_>(m_sub, "COOTensorType") .def(py::init()) - .def_property_readonly("ElementType", &SparseTensorType::element, "Get the SparseTensorType's element type."); + .def_property_readonly("ElementType", &COOTensorType::element, "Get the COOTensorType's element type."); (void)py::class_>(m_sub, "CSRTensorType") .def(py::init()) .def_property_readonly("ElementType", &CSRTensorType::element, "Get the CSRTensorType's element type."); diff --git a/mindspore/ccsrc/pybind_api/ir/tensor_py.cc b/mindspore/ccsrc/pybind_api/ir/tensor_py.cc index fa304199771b..15a5db728d04 100644 --- a/mindspore/ccsrc/pybind_api/ir/tensor_py.cc +++ b/mindspore/ccsrc/pybind_api/ir/tensor_py.cc @@ -16,6 +16,8 @@ #include "pybind_api/ir/tensor_py.h" +#include + #include "pybind_api/api_register.h" #include "abstract/abstract_value.h" #include "utils/shape_utils.h" @@ -23,6 +25,11 @@ namespace mindspore { namespace tensor { +constexpr ssize_t kPyBufItemSize1 = 1; +constexpr ssize_t kPyBufItemSize2 = 2; +constexpr ssize_t kPyBufItemSize4 = 4; +constexpr ssize_t kPyBufItemSize8 = 8; + static TypeId GetDataType(const py::buffer_info &buf) { if (buf.format.size() == 1) { switch (buf.format.front()) { @@ -30,11 +37,11 @@ static TypeId GetDataType(const py::buffer_info &buf) { case 'f': case 'd': switch (buf.itemsize) { - case 2: + case kPyBufItemSize2: return TypeId::kNumberTypeFloat16; - case 4: + case kPyBufItemSize4: return TypeId::kNumberTypeFloat32; - case 8: + case kPyBufItemSize8: return TypeId::kNumberTypeFloat64; } break; @@ -44,13 +51,13 @@ static TypeId GetDataType(const py::buffer_info &buf) { case 'l': case 'q': switch (buf.itemsize) { - case 1: + case kPyBufItemSize1: return TypeId::kNumberTypeInt8; - case 2: + case kPyBufItemSize2: return TypeId::kNumberTypeInt16; - case 4: + case kPyBufItemSize4: return TypeId::kNumberTypeInt32; - case 8: + case kPyBufItemSize8: return TypeId::kNumberTypeInt64; } break; @@ -60,13 +67,13 @@ static TypeId GetDataType(const py::buffer_info &buf) { case 'L': case 'Q': switch (buf.itemsize) { - case 1: + case kPyBufItemSize1: return TypeId::kNumberTypeUInt8; - case 2: + case kPyBufItemSize2: return TypeId::kNumberTypeUInt16; - case 4: + case kPyBufItemSize4: return TypeId::kNumberTypeUInt32; - case 8: + case kPyBufItemSize8: return TypeId::kNumberTypeUInt64; } break; @@ -665,5 +672,34 @@ REGISTER_PYBIND_DEFINE( .def("__str__", &CSRTensor::ToString) .def("__repr__", &CSRTensor::ToString); })); + +py::tuple COOTensorPy::GetPyTupleShape(const COOTensor &coo_tensor) { + auto &shape = coo_tensor.shape(); + py::tuple dims(shape.size()); + for (size_t i = 0; i < dims.size(); ++i) { + dims[i] = py::int_(shape[i]); + } + return dims; +} + +REGISTER_PYBIND_DEFINE(COOTensor, ([](const py::module *m) { + // Define python COOTensor class. + (void)py::class_>(*m, "COOTensor") + .def(py::init([](const Tensor &indices, const Tensor &values, const py::tuple &shape) { + return std::make_shared(std::make_shared(indices), + std::make_shared(values), + GetShapeFromTuple(shape)); + }), + py::arg("indices"), py::arg("values"), py::arg("shape")) + .def(py::init( + [](const COOTensor &coo_tensor) { return std::make_shared(coo_tensor); }), + py::arg("input")) + .def_property_readonly("_shape", COOTensorPy::GetPyTupleShape) + .def_property_readonly("_dtype", &COOTensor::Dtype) + .def_property_readonly("_indices", &COOTensor::GetIndices) + .def_property_readonly("_values", &COOTensor::GetValues) + .def("__str__", &COOTensor::ToString) + .def("__repr__", &COOTensor::ToString); + })); } // namespace tensor } // namespace mindspore diff --git a/mindspore/ccsrc/pybind_api/ir/tensor_py.h b/mindspore/ccsrc/pybind_api/ir/tensor_py.h index 3e2d1095e96c..fa5bd2a97fb7 100644 --- a/mindspore/ccsrc/pybind_api/ir/tensor_py.h +++ b/mindspore/ccsrc/pybind_api/ir/tensor_py.h @@ -124,6 +124,12 @@ class CSRTensorPy { public: static py::tuple GetPyTupleShape(const CSRTensor &csr_tensor); }; + +// COOTensor python wrapper and adapter class. +class COOTensorPy { + public: + static py::tuple GetPyTupleShape(const COOTensor &coo_tensor); +}; } // namespace tensor } // namespace mindspore diff --git a/mindspore/ccsrc/utils/convert_utils.h b/mindspore/ccsrc/utils/convert_utils.h index f82f79f9dcc6..324fadeb7945 100644 --- a/mindspore/ccsrc/utils/convert_utils.h +++ b/mindspore/ccsrc/utils/convert_utils.h @@ -83,18 +83,20 @@ size_t CountValueNum(const ValueTuplePtr &value_tuple); // sparse_attr_map converts CNode{kPrimSparseGetAttr, SparseTensor} // to CNode{kPrimTupleGetItem, SparseTensor, int64_t(index)}, used // in backend common optimization pass: sparse_process.cc -const mindspore::HashMap sparse_attr_map = {{prim::kPrimCSRTensorGetIndptr->name(), 0}, - {prim::kPrimCSRTensorGetIndices->name(), 1}, - {prim::kPrimCSRTensorGetValues->name(), 2}, - {prim::kPrimCSRTensorGetDenseShape->name(), 3}}; +const mindspore::HashMap sparse_attr_map = { + {prim::kPrimCSRTensorGetIndptr->name(), 0}, {prim::kPrimCSRTensorGetIndices->name(), 1}, + {prim::kPrimCSRTensorGetValues->name(), 2}, {prim::kPrimCSRTensorGetDenseShape->name(), 3}, + {prim::kPrimCOOTensorGetIndices->name(), 0}, {prim::kPrimCOOTensorGetValues->name(), 1}, + {prim::kPrimCOOTensorGetDenseShape->name(), 2}}; // make_sparse_set records all make_sparse primitives, and tries to replace // make_sparse to make_tuple, used in backend common optimization pass: // sparse_process.cc -const mindspore::HashSet make_sparse_set = {{prim::kPrimMakeCSRTensor->name()}}; +const mindspore::HashSet make_sparse_set = {{prim::kPrimMakeCSRTensor->name()}, + {prim::kPrimMakeCOOTensor->name()}}; // sparse_op_set records all sparse_compute operators, which takes sparsetensor // and (possibly) dense tensors, used in backend common optimization pass: // sparse_process.cc -const mindspore::HashSet sparse_op_set = {{prim::kPrimSparseTensorDenseMatmul->name()}, +const mindspore::HashSet sparse_op_set = {{prim::kPrimCOOTensorDenseMatmul->name()}, {prim::kPrimCSRDenseMul->name()}, {prim::kPrimCSRReduceSum->name()}, {prim::kPrimCSRMV->name()}, diff --git a/mindspore/ccsrc/utils/convert_utils_py.cc b/mindspore/ccsrc/utils/convert_utils_py.cc index b7de9e11202c..322e2715da2f 100644 --- a/mindspore/ccsrc/utils/convert_utils_py.cc +++ b/mindspore/ccsrc/utils/convert_utils_py.cc @@ -47,6 +47,8 @@ py::object VectorRefToPyData(const VectorRef &value_list); py::object VectorRefToPyData(const VectorRef &value_list, const AbstractBasePtr &output); // Wrap VectorRef to CSRTensor py::object MakeCSRTensor(const VectorRef &value_list); +py::object MakeCOOTensor(const VectorRef &value_list); +ShapeVector ConvertToShapeVector(const ValuePtr &shape_ptr, const VectorRef &value_list, size_t shape_idx); py::object CSRTensorToPyData(const tensor::CSRTensorPtr &csr_tensor) { auto ref = py::tuple(1); ref[0] = csr_tensor; @@ -295,7 +297,7 @@ py::object AnyToPyData(const Any &value) { py::object BaseRefToPyData(const BaseRef &value, const AbstractBasePtr &output) { py::object ret; - // If output value is a tuple, check if abstract is a SparseTensor in funcgraph output + // If output value is a tuple, check if abstract is a COOTensor in funcgraph output if (utils::isa(value)) { MS_LOG(DEBUG) << "BaseRefToPyData, value is tuple: " << value.ToString(); auto vec_ref = utils::cast(value); @@ -415,10 +417,13 @@ py::object VectorRefToPyData(const VectorRef &value_list) { py::object VectorRefToPyData(const VectorRef &value_list, const AbstractBasePtr &output) { MS_LOG(DEBUG) << "vector_ref"; - // Current VectorRef reflects a SparseTensor type + // Current VectorRef reflects a COOTensor type if (output->isa()) { return MakeCSRTensor(value_list); } + if (output->isa()) { + return MakeCOOTensor(value_list); + } py::object ret; size_t value_size = value_list.size(); auto ref_tuple = py::tuple(value_size); @@ -626,20 +631,10 @@ bool IsGraphOutputValueNodeOrParameter(const AnfNodePtr &output, const py::tuple return false; } -py::object MakeCSRTensor(const VectorRef &value_list) { - constexpr size_t kCSRTensorInputSize{4}; - if (value_list.size() != kCSRTensorInputSize) { - MS_LOG(EXCEPTION) << "CSRTensor must have 4 inputs."; - } - using TensorPtr = tensor::TensorPtr; - using CSRTensor = tensor::CSRTensor; - TensorPtr indptr = utils::cast(value_list[0]); - TensorPtr indices = utils::cast(value_list[1]); - TensorPtr values = utils::cast(value_list[2]); - ValuePtr shape_ptr = utils::cast(value_list[3]); +ShapeVector ConvertToShapeVector(const ValuePtr &shape_ptr, const VectorRef &value_list, size_t shape_idx) { + MS_EXCEPTION_IF_NULL(shape_ptr); + ShapeVector shape; ValueTuplePtr shape_tuple = shape_ptr->cast(); - ShapeVector shape{}; - // CSRTensor shape is a tuple on GPU and CPU if (shape_tuple) { for (const auto &v : shape_tuple->value()) { MS_EXCEPTION_IF_NULL(v); @@ -647,22 +642,59 @@ py::object MakeCSRTensor(const VectorRef &value_list) { MS_EXCEPTION_IF_NULL(scalar); shape.push_back(GetValue(scalar)); } - // CSRTensor shape is a VectorRef(TensorPtr, TensorPtr) on Ascend } else { - auto shape_ref = utils::cast(value_list[3]); + auto shape_ref = utils::cast(value_list[shape_idx]); MS_EXCEPTION_IF_NULL(shape_ref); for (const auto &v : shape_ref) { MS_EXCEPTION_IF_NULL(v); - auto tensorptr = utils::cast(v); + auto tensorptr = utils::cast(v); MS_EXCEPTION_IF_NULL(tensorptr); if (tensorptr->DataDim() != 0) { - MS_LOG(EXCEPTION) << "Element in CSRTensor's shape must be scalar!"; + MS_LOG(EXCEPTION) << "Element in COOTensor's shape must be scalar!"; } - tensorptr->data_sync(false); shape.push_back(*(static_cast(tensorptr->data_c()))); } } + return shape; +} + +py::object MakeCSRTensor(const VectorRef &value_list) { + constexpr size_t kCSRTensorInputSize{4}; + if (value_list.size() != kCSRTensorInputSize) { + MS_LOG(EXCEPTION) << "CSRTensor must have 4 inputs."; + } + using TensorPtr = tensor::TensorPtr; + using CSRTensor = tensor::CSRTensor; + constexpr size_t kIndptrIdx{0}; + constexpr size_t kIndicesIdx{1}; + constexpr size_t kValuesIdx{2}; + constexpr size_t kShapeIdx{3}; + TensorPtr indptr = utils::cast(value_list[kIndptrIdx]); + TensorPtr indices = utils::cast(value_list[kIndicesIdx]); + TensorPtr values = utils::cast(value_list[kValuesIdx]); + ValuePtr shape_ptr = utils::cast(value_list[kShapeIdx]); + + ShapeVector shape = ConvertToShapeVector(shape_ptr, value_list, kShapeIdx); auto csr_tensor_ptr = std::make_shared(indptr, indices, values, shape); return CSRTensorToPyData(csr_tensor_ptr); } + +py::object MakeCOOTensor(const VectorRef &value_list) { + constexpr size_t kCOOTensorInputSize{3}; + constexpr size_t kIndicesIdx{0}; + constexpr size_t kValuesIdx{1}; + constexpr size_t kShapeIdx{2}; + if (value_list.size() != kCOOTensorInputSize) { + MS_LOG(EXCEPTION) << "COOTensor must have " << kCOOTensorInputSize << "inputs."; + } + tensor::TensorPtr indices = utils::cast(value_list[kIndicesIdx]); + tensor::TensorPtr values = utils::cast(value_list[kValuesIdx]); + ValuePtr shape_ptr = utils::cast(value_list[kShapeIdx]); + + ShapeVector shape = ConvertToShapeVector(shape_ptr, value_list, kShapeIdx); + auto ref = py::tuple(1); + auto coo_tensor_ptr = std::make_shared(indices, values, shape); + ref[0] = coo_tensor_ptr; + return ref[0]; +} } // namespace mindspore diff --git a/mindspore/ccsrc/vm/backend.cc b/mindspore/ccsrc/vm/backend.cc index 2996edda1f4e..f3b25e186ef0 100644 --- a/mindspore/ccsrc/vm/backend.cc +++ b/mindspore/ccsrc/vm/backend.cc @@ -1017,7 +1017,7 @@ void MindRTBackend::ConstructOutputs(const AnfNodePtr &output_node, const PrimitiveSet expand_prims{ prim::kPrimMakeTuple, prim::kPrimMakeCSRTensor, - prim::kPrimMakeSparseTensor, + prim::kPrimMakeCOOTensor, prim::kPrimMakeRowTensor, }; // The MakeTuple/MakeSaprse node need expand and recurse. diff --git a/mindspore/core/abstract/abstract_value.cc b/mindspore/core/abstract/abstract_value.cc index 7d2f00f5d65c..e8fbfa7ea75a 100644 --- a/mindspore/core/abstract/abstract_value.cc +++ b/mindspore/core/abstract/abstract_value.cc @@ -1461,16 +1461,16 @@ std::string AbstractRowTensor::ToString() const { return buffer.str(); } -// SparseTensor -TypePtr AbstractSparseTensor::BuildType() const { +// COOTensor +TypePtr AbstractCOOTensor::BuildType() const { MS_EXCEPTION_IF_NULL(element()); TypePtr element_type = element()->BuildType(); - return std::make_shared(element_type); + return std::make_shared(element_type); } -AbstractBasePtr AbstractSparseTensor::Clone() const { +AbstractBasePtr AbstractCOOTensor::Clone() const { MS_EXCEPTION_IF_NULL(element()); - auto clone = std::make_shared(element()->Clone()); + auto clone = std::make_shared(element()->Clone()); ShapePtr shp = shape(); MS_EXCEPTION_IF_NULL(shp); clone->set_shape(shp->Clone()); @@ -1490,9 +1490,9 @@ AbstractBasePtr AbstractSparseTensor::Clone() const { return clone; } -AbstractBasePtr AbstractSparseTensor::Broaden() const { +AbstractBasePtr AbstractCOOTensor::Broaden() const { MS_EXCEPTION_IF_NULL(element()); - auto broaden = std::make_shared(element()->Broaden()); + auto broaden = std::make_shared(element()->Broaden()); auto shp = shape(); MS_EXCEPTION_IF_NULL(shp); MS_EXCEPTION_IF_NULL(indices_); @@ -1512,9 +1512,9 @@ AbstractBasePtr AbstractSparseTensor::Broaden() const { return broaden; } -AbstractBasePtr AbstractSparseTensor::BroadenWithShape() const { +AbstractBasePtr AbstractCOOTensor::BroadenWithShape() const { MS_EXCEPTION_IF_NULL(element()); - auto broaden = std::make_shared(element()->Broaden()); + auto broaden = std::make_shared(element()->Broaden()); auto this_shape = shape(); MS_EXCEPTION_IF_NULL(this_shape); auto shp = this_shape->Clone(); @@ -1537,7 +1537,7 @@ AbstractBasePtr AbstractSparseTensor::BroadenWithShape() const { return broaden; } -std::string AbstractSparseTensor::ToString() const { +std::string AbstractCOOTensor::ToString() const { std::ostringstream buffer; BaseShapePtr shape_track = GetShapeTrack(); MS_EXCEPTION_IF_NULL(shape_track); diff --git a/mindspore/core/abstract/abstract_value.h b/mindspore/core/abstract/abstract_value.h index 971fcf2c172e..bb6530d72c0d 100644 --- a/mindspore/core/abstract/abstract_value.h +++ b/mindspore/core/abstract/abstract_value.h @@ -1482,28 +1482,28 @@ class MS_CORE_API AbstractRowTensor final : public AbstractUndetermined { AbstractTuplePtr dense_shape_; }; -/// \brief Class AbstractSparseTensor describes a SparseTensor's abstract value. -class MS_CORE_API AbstractSparseTensor final : public AbstractUndetermined { +/// \brief Class AbstractCOOTensor describes a COOTensor's abstract value. +class MS_CORE_API AbstractCOOTensor final : public AbstractUndetermined { public: - /// \brief Constructor of AbstractSparseTensor. + /// \brief Constructor of AbstractCOOTensor. /// - /// \param[in] element The abstract which is wrapped to be the abstract value of SparseTensor. + /// \param[in] element The abstract which is wrapped to be the abstract value of COOTensor. /// \param[in] shape The dimension of the abstract. - explicit AbstractSparseTensor(const AbstractBasePtr &element, const BaseShapePtr &shape = std::make_shared()) + explicit AbstractCOOTensor(const AbstractBasePtr &element, const BaseShapePtr &shape = std::make_shared()) : AbstractUndetermined(element, shape) {} - /// \brief Constructor of AbstractSparseTensor. + /// \brief Constructor of AbstractCOOTensor. /// - /// \param[in] element_type The type of SparseTensor. - /// \param[in] shape The dimension of SparseTensor. - AbstractSparseTensor(const TypePtr &element_type, const ShapeVector &shape) + /// \param[in] element_type The type of COOTensor. + /// \param[in] shape The dimension of COOTensor. + AbstractCOOTensor(const TypePtr &element_type, const ShapeVector &shape) : AbstractUndetermined(element_type, shape) {} - /// \brief Destructor of AbstractSparseTensor. - ~AbstractSparseTensor() override = default; - MS_DECLARE_PARENT(AbstractSparseTensor, AbstractUndetermined) + /// \brief Destructor of AbstractCOOTensor. + ~AbstractCOOTensor() override = default; + MS_DECLARE_PARENT(AbstractCOOTensor, AbstractUndetermined) - /// \brief Get the indices of SparseTensor. + /// \brief Get the indices of COOTensor. /// /// \return A pointer to the abstract tensor. const AbstractTensorPtr indices() const { return indices_; } @@ -1520,7 +1520,7 @@ class MS_CORE_API AbstractSparseTensor final : public AbstractUndetermined { /// \brief Set the values. /// - /// \param[in] values The values of SparseTensor. + /// \param[in] values The values of COOTensor. void set_values(const AbstractTensorPtr &values) { values_ = values; } /// \brief Get the dense shape. @@ -1530,7 +1530,7 @@ class MS_CORE_API AbstractSparseTensor final : public AbstractUndetermined { /// \brief Set the dense shape. /// - /// \param[in] dense_shape The dense shape of SparseTensor. + /// \param[in] dense_shape The dense shape of COOTensor. void set_dense_shape(const AbstractTuplePtr &dense_shape) { dense_shape_ = dense_shape; } TypePtr BuildType() const override; diff --git a/mindspore/core/abstract/infer_functions.h b/mindspore/core/abstract/infer_functions.h index 8360b8b295e4..dade2e47e42c 100644 --- a/mindspore/core/abstract/infer_functions.h +++ b/mindspore/core/abstract/infer_functions.h @@ -149,14 +149,14 @@ AbstractBasePtr InferImplDebug(const AnalysisEnginePtr &, const PrimitivePtr &pr const AbstractBasePtrList &args_spec_list); template std::shared_ptr InferSparseAttr(const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list); -AbstractBasePtr InferImplMakeSparseTensor(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list); -AbstractBasePtr InferImplSparseTensorGetValues(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list); -AbstractBasePtr InferImplSparseTensorGetIndices(const AnalysisEnginePtr &, const PrimitivePtr &primitive, +AbstractBasePtr InferImplMakeCOOTensor(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list); +AbstractBasePtr InferImplCOOTensorGetValues(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list); +AbstractBasePtr InferImplCOOTensorGetIndices(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list); +AbstractBasePtr InferImplCOOTensorGetDenseShape(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list); -AbstractBasePtr InferImplSparseTensorGetDenseShape(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list); AbstractBasePtr InferImplCSRMul(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list); AbstractBasePtr InferImplCSRMV(const AnalysisEnginePtr &, const PrimitivePtr &primitive, diff --git a/mindspore/core/abstract/param_validator.h b/mindspore/core/abstract/param_validator.h index 169259fda216..aea03dbfeb62 100644 --- a/mindspore/core/abstract/param_validator.h +++ b/mindspore/core/abstract/param_validator.h @@ -81,7 +81,7 @@ ABSTRACT_REPORT_NAME_TRAITS(Type) ABSTRACT_REPORT_NAME_TRAITS(KeywordArg) ABSTRACT_REPORT_NAME_TRAITS(Class) ABSTRACT_REPORT_NAME_TRAITS(RowTensor) -ABSTRACT_REPORT_NAME_TRAITS(SparseTensor) +ABSTRACT_REPORT_NAME_TRAITS(COOTensor) ABSTRACT_REPORT_NAME_TRAITS(CSRTensor) ABSTRACT_REPORT_NAME_TRAITS(Sequence) diff --git a/mindspore/core/abstract/prim_others.cc b/mindspore/core/abstract/prim_others.cc index 466d73f5fb29..cb3be974d2b4 100644 --- a/mindspore/core/abstract/prim_others.cc +++ b/mindspore/core/abstract/prim_others.cc @@ -316,8 +316,8 @@ AbstractBasePtr InferImplRowTensorAdd(const AnalysisEnginePtr &, const Primitive return args_spec_list[0]; } -AbstractBasePtr InferImplMakeSparseTensor(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { +AbstractBasePtr InferImplMakeCOOTensor(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { // Inputs: two tensors and a tuple. constexpr auto kMakeSparseInputNum = 3; const std::string op_name = primitive->name(); @@ -369,39 +369,39 @@ AbstractBasePtr InferImplMakeSparseTensor(const AnalysisEnginePtr &, const Primi << dense_shape_value->ToString(); } } - auto ret = std::make_shared(values->element()->BuildType(), dense_shape_vec); + auto ret = std::make_shared(values->element()->BuildType(), dense_shape_vec); ret->set_indices(indices); ret->set_values(values); ret->set_dense_shape(dense_shape); return ret; } -AbstractBasePtr InferImplSparseTensorGetValues(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { +AbstractBasePtr InferImplCOOTensorGetValues(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { // Inputs: two tensors and a tuple. const std::string op_name = primitive->name(); CheckArgsSize(op_name, args_spec_list, 1); - auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); + auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); MS_EXCEPTION_IF_NULL(sparse_tensor->values()); return sparse_tensor->values(); } -AbstractBasePtr InferImplSparseTensorGetIndices(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { +AbstractBasePtr InferImplCOOTensorGetIndices(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { // Inputs: two tensors and a tuple. const std::string op_name = primitive->name(); CheckArgsSize(op_name, args_spec_list, 1); - auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); + auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); MS_EXCEPTION_IF_NULL(sparse_tensor->indices()); return sparse_tensor->indices(); } -AbstractBasePtr InferImplSparseTensorGetDenseShape(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { +AbstractBasePtr InferImplCOOTensorGetDenseShape(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { // Inputs: two tensors and a tuple. const std::string op_name = primitive->name(); CheckArgsSize(op_name, args_spec_list, 1); - auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); + auto sparse_tensor = CheckArg(op_name, args_spec_list, 0); MS_EXCEPTION_IF_NULL(sparse_tensor->dense_shape()); return sparse_tensor->dense_shape(); } diff --git a/mindspore/core/abstract/primitive_infer_map.cc b/mindspore/core/abstract/primitive_infer_map.cc index d2cfc4901636..24ed0521ac1a 100644 --- a/mindspore/core/abstract/primitive_infer_map.cc +++ b/mindspore/core/abstract/primitive_infer_map.cc @@ -215,11 +215,11 @@ PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap() { {prim::kPrimDebug, R{InferImplDebug, nullptr, true}}, // Dynamic shape testing {prim::kPrimGpuConvertToDynamicShape, R{InferImplGpuConvertToDynamicShape, nullptr, true}}, - // SparseTensor - {prim::kPrimMakeSparseTensor, R{InferImplMakeSparseTensor, nullptr, true}}, - {prim::kPrimSparseTensorGetValues, R{InferImplSparseTensorGetValues, nullptr, true}}, - {prim::kPrimSparseTensorGetIndices, R{InferImplSparseTensorGetIndices, nullptr, true}}, - {prim::kPrimSparseTensorGetDenseShape, R{InferImplSparseTensorGetDenseShape, nullptr, true}}, + // COOTensor + {prim::kPrimMakeCOOTensor, R{InferImplMakeCOOTensor, nullptr, true}}, + {prim::kPrimCOOTensorGetValues, R{InferImplCOOTensorGetValues, nullptr, true}}, + {prim::kPrimCOOTensorGetIndices, R{InferImplCOOTensorGetIndices, nullptr, true}}, + {prim::kPrimCOOTensorGetDenseShape, R{InferImplCOOTensorGetDenseShape, nullptr, true}}, // RowTensor {prim::kPrimMakeRowTensor, R{InferImplMakeRowTensor, nullptr, true}}, {prim::kPrimRowTensorGetValues, R{InferImplRowTensorGetValues, nullptr, true}}, diff --git a/mindspore/core/base/core_ops.h b/mindspore/core/base/core_ops.h index 796f3ec049b6..c354d639f689 100644 --- a/mindspore/core/base/core_ops.h +++ b/mindspore/core/base/core_ops.h @@ -138,6 +138,13 @@ constexpr auto kCSRTensorGetIndptr = "CSRTensorGetIndptr"; constexpr auto kCSRTensorGetIndices = "CSRTensorGetIndices"; constexpr auto kCSRTensorGetDenseShape = "CSRTensorGetDenseShape"; +// COOTensor +constexpr auto kMakeCOOTensor = "MakeCOOTensor"; +constexpr auto kCOOTensorGetValues = "COOTensorGetValues"; +constexpr auto kCOOTensorGetIndices = "COOTensorGetIndices"; +constexpr auto kCOOTensorGetDenseShapes = "COOTensorGetDenseShape"; +constexpr auto kCOOTensorDenseMatmul = "COOTensorDenseMatmul"; + // Sparse ops constexpr auto kSparseTensorDenseMatmul = "SparseTensorDenseMatmul"; constexpr auto kCSRDenseMul = "CSRDenseMul"; @@ -565,13 +572,12 @@ MS_CORE_API inline const PrimitivePtr kPrimRowTensorGetDenseShape = std::make_shared("RowTensorGetDenseShape"); MS_CORE_API inline const PrimitivePtr kPrimRowTensorAdd = std::make_shared("RowTensorAdd"); -// SparseTensor -MS_CORE_API inline const PrimitivePtr kPrimMakeSparseTensor = std::make_shared("MakeSparseTensor"); -MS_CORE_API inline const PrimitivePtr kPrimSparseTensorGetValues = std::make_shared("SparseTensorGetValues"); -MS_CORE_API inline const PrimitivePtr kPrimSparseTensorGetIndices = - std::make_shared("SparseTensorGetIndices"); -MS_CORE_API inline const PrimitivePtr kPrimSparseTensorGetDenseShape = - std::make_shared("SparseTensorGetDenseShape"); +// COOTensor +MS_CORE_API inline const PrimitivePtr kPrimMakeCOOTensor = std::make_shared(kMakeCOOTensor); +MS_CORE_API inline const PrimitivePtr kPrimCOOTensorGetValues = std::make_shared(kCOOTensorGetValues); +MS_CORE_API inline const PrimitivePtr kPrimCOOTensorGetIndices = std::make_shared(kCOOTensorGetIndices); +MS_CORE_API inline const PrimitivePtr kPrimCOOTensorGetDenseShape = + std::make_shared(kCOOTensorGetDenseShapes); // CSRTensor MS_CORE_API inline const PrimitivePtr kPrimMakeCSRTensor = std::make_shared(kMakeCSRTensor); @@ -584,6 +590,7 @@ MS_CORE_API inline const PrimitivePtr kPrimCSRTensorGetDenseShape = // Sparse ops MS_CORE_API inline const PrimitivePtr kPrimSparseTensorDenseMatmul = std::make_shared(kSparseTensorDenseMatmul); +MS_CORE_API inline const PrimitivePtr kPrimCOOTensorDenseMatmul = std::make_shared(kCOOTensorDenseMatmul); MS_CORE_API inline const PrimitivePtr kPrimCSRDenseMul = std::make_shared(kCSRDenseMul); MS_CORE_API inline const PrimitivePtr kPrimCSRReduceSum = std::make_shared(kCSRReduceSum); MS_CORE_API inline const PrimitivePtr kPrimCSRMV = std::make_shared(kCSRMV); diff --git a/mindspore/core/ir/dtype/tensor_type.cc b/mindspore/core/ir/dtype/tensor_type.cc index f1d2da355f4a..49ac586716e2 100644 --- a/mindspore/core/ir/dtype/tensor_type.cc +++ b/mindspore/core/ir/dtype/tensor_type.cc @@ -147,40 +147,40 @@ bool RowTensorType::operator==(const Type &other) const { return *element_type_ == *other_elem_type; } -TypePtr SparseTensorType::DeepCopy() const { +TypePtr COOTensorType::DeepCopy() const { MS_EXCEPTION_IF_NULL(element_type_); if (IsGeneric()) { - return std::make_shared(); + return std::make_shared(); } - return std::make_shared(element_type_->DeepCopy()); + return std::make_shared(element_type_->DeepCopy()); } -std::string SparseTensorType::ToReprString() const { +std::string COOTensorType::ToReprString() const { if (element_type_ == nullptr) { - return "SparseTensor"; + return "COOTensor"; } - return "SparseTensor[" + element_type_->ToReprString() + "]"; + return "COOTensor[" + element_type_->ToReprString() + "]"; } -std::string SparseTensorType::ToString() const { +std::string COOTensorType::ToString() const { if (element_type_ == nullptr) { - return "SparseTensor"; + return "COOTensor"; } - return "SparseTensor[" + element_type_->ToString() + "]"; + return "COOTensor[" + element_type_->ToString() + "]"; } -std::string SparseTensorType::DumpText() const { +std::string COOTensorType::DumpText() const { if (element_type_ == nullptr) { - return "SparseTensor"; + return "COOTensor"; } - return "SparseTensor[" + element_type_->DumpText() + "]"; + return "COOTensor[" + element_type_->DumpText() + "]"; } -bool SparseTensorType::operator==(const Type &other) const { +bool COOTensorType::operator==(const Type &other) const { if (!IsSameObjectType(*this, other)) { return false; } - auto other_elem_type = static_cast(other).element_type_; + auto other_elem_type = static_cast(other).element_type_; if (element_type_ == nullptr && other_elem_type == nullptr) { return true; } else if (element_type_ == nullptr || other_elem_type == nullptr) { diff --git a/mindspore/core/ir/dtype/tensor_type.h b/mindspore/core/ir/dtype/tensor_type.h index 50be84f7d235..7f8772f4ff8c 100644 --- a/mindspore/core/ir/dtype/tensor_type.h +++ b/mindspore/core/ir/dtype/tensor_type.h @@ -154,29 +154,29 @@ class MS_CORE_API RowTensorType final : public Object { using RowTensorTypePtr = std::shared_ptr; /// \brief SparseTensorType defines interface for sparse tensor data type. -class MS_CORE_API SparseTensorType final : public Object { +class MS_CORE_API COOTensorType final : public Object { public: - /// \brief Default constructor for SparseTensorType. - SparseTensorType() : Object(kObjectTypeSparseTensorType, kObjectTypeUndeterminedType) {} + /// \brief Default constructor for COOTensorType. + COOTensorType() : Object(kObjectTypeCOOTensorType, kObjectTypeUndeterminedType) {} - /// \brief Constructor for SparseTensorType. + /// \brief Constructor for COOTensorType. /// - /// \param[in] ele The element of SparseTensorType. - explicit SparseTensorType(const TypePtr &ele) - : Object(kObjectTypeSparseTensorType, kObjectTypeUndeterminedType, false), element_type_(ele) {} + /// \param[in] ele The element of COOTensorType. + explicit COOTensorType(const TypePtr &ele) + : Object(kObjectTypeCOOTensorType, kObjectTypeUndeterminedType, false), element_type_(ele) {} - /// \brief Destructor of SparseTensorType. - ~SparseTensorType() override = default; - MS_DECLARE_PARENT(SparseTensorType, Object) + /// \brief Destructor of COOTensorType. + ~COOTensorType() override = default; + MS_DECLARE_PARENT(COOTensorType, Object) - TypeId generic_type_id() const override { return kObjectTypeSparseTensorType; } + TypeId generic_type_id() const override { return kObjectTypeCOOTensorType; } - /// \brief Get the element of SparseTensorType object. + /// \brief Get the element of COOTensorType object. /// - /// \return The element of SparseTensorType object. + /// \return The element of COOTensorType object. const TypePtr element() const { return element_type_; } - /// \brief Set the element of SparseTensorType object. + /// \brief Set the element of COOTensorType object. /// /// \param[in] element_type Define the element type to be set. void set_element(const TypePtr &element_type) { element_type_ = element_type; } @@ -190,7 +190,7 @@ class MS_CORE_API SparseTensorType final : public Object { private: TypePtr element_type_; }; -using SparseTensorTypePtr = std::shared_ptr; +using COOTensorTypePtr = std::shared_ptr; /// \brief CSRTensorType defines interface for sparse tensor data type. class MS_CORE_API CSRTensorType : public Object { diff --git a/mindspore/core/ir/dtype/type.cc b/mindspore/core/ir/dtype/type.cc index 8bd1ed601f99..e63d20f0e559 100644 --- a/mindspore/core/ir/dtype/type.cc +++ b/mindspore/core/ir/dtype/type.cc @@ -48,7 +48,7 @@ static mindspore::HashMap g_type_2_lable{ {kObjectTypeKeyword, MS_TYPE2LABLE(kObjectTypeKeyword)}, {kObjectTypeTensorType, MS_TYPE2LABLE(kObjectTypeTensorType)}, {kObjectTypeRowTensorType, MS_TYPE2LABLE(kObjectTypeRowTensorType)}, - {kObjectTypeSparseTensorType, MS_TYPE2LABLE(kObjectTypeSparseTensorType)}, + {kObjectTypeCOOTensorType, MS_TYPE2LABLE(kObjectTypeCOOTensorType)}, {kObjectTypeCSRTensorType, MS_TYPE2LABLE(kObjectTypeCSRTensorType)}, {kObjectTypeUndeterminedType, MS_TYPE2LABLE(kObjectTypeUndeterminedType)}, {kObjectTypeClass, MS_TYPE2LABLE(kObjectTypeClass)}, diff --git a/mindspore/core/ir/dtype_extends.cc b/mindspore/core/ir/dtype_extends.cc index 40e25f4db001..24e1d0ade3eb 100644 --- a/mindspore/core/ir/dtype_extends.cc +++ b/mindspore/core/ir/dtype_extends.cc @@ -64,7 +64,7 @@ std::string GetExcptionTypeString(TypeId id) { {kMetaTypeObject, "MetaTypeObject"}, {kObjectTypeNumber, "Number"}, {kObjectTypeRowTensorType, "RowTensor"}, - {kObjectTypeSparseTensorType, "SparseTensor"}, + {kObjectTypeCOOTensorType, "COOTensor"}, {kObjectTypeUndeterminedType, "Undetermined"}, {kObjectTypeClass, "Class"}, {kObjectTypeFunction, "Function"}, @@ -229,9 +229,9 @@ TypePtr RowTensorStrToType(const std::string &type_name) { return std::make_shared(element_type); } -TypePtr SparseTensorStrToType(const std::string &type_name) { - if (type_name == "SparseTensor") { - return std::make_shared(); +TypePtr COOTensorStrToType(const std::string &type_name) { + if (type_name == "COOTensor") { + return std::make_shared(); } auto start = type_name.find_first_of('[') + 1; auto end = type_name.find_last_of(']'); @@ -243,7 +243,7 @@ TypePtr SparseTensorStrToType(const std::string &type_name) { if (element_type == nullptr) { return nullptr; } - return std::make_shared(element_type); + return std::make_shared(element_type); } TypePtr CSRTensorStrToType(const std::string &type_name) { @@ -417,7 +417,7 @@ TypePtr GetTypeByStringStarts(const std::string &type_name) { {"Tensor", [](const std::string &type_name) -> TypePtr { return TensorStrToType(type_name); }}, {"Undetermined", [](const std::string &type_name) -> TypePtr { return UndeterminedStrToType(type_name); }}, {"RowTensor", [](const std::string &type_name) -> TypePtr { return RowTensorStrToType(type_name); }}, - {"SparseTensor", [](const std::string &type_name) -> TypePtr { return SparseTensorStrToType(type_name); }}, + {"COOTensor", [](const std::string &type_name) -> TypePtr { return COOTensorStrToType(type_name); }}, {"CSRTensor", [](const std::string &type_name) -> TypePtr { return CSRTensorStrToType(type_name); }}, {"List", [](const std::string &type_name) -> TypePtr { return ListStrToType(type_name); }}, {"Tuple", [](const std::string &type_name) -> TypePtr { return TupleStrToType(type_name); }}, diff --git a/mindspore/core/ir/tensor.cc b/mindspore/core/ir/tensor.cc index 472316ea547d..49dee71182c9 100644 --- a/mindspore/core/ir/tensor.cc +++ b/mindspore/core/ir/tensor.cc @@ -15,7 +15,12 @@ */ #include "ir/tensor.h" + #include +#include +#include +#include + #include "abstract/utils.h" #include "abstract/abstract_value.h" #include "base/complex_storage.h" @@ -704,5 +709,34 @@ abstract::AbstractBasePtr CSRTensor::ToAbstract() { return abs_csr_tensor; } + +std::string COOTensor::ToString() const { + std::ostringstream buf; + MS_EXCEPTION_IF_NULL(indices_); + MS_EXCEPTION_IF_NULL(values_); + auto dtype = values_->Dtype(); + buf << "COOTensor(shape=" << ShapeToString(shape_) << ", dtype=" << dtype->ToString() + << ", indices=" << indices_->ToString() << ", values=" << values_->ToString() << ")"; + return buf.str(); +} + +abstract::AbstractBasePtr COOTensor::ToAbstract() { + auto dtype = values_->Dtype(); + if (!IsSubType(dtype, kNumber) && !IsSubType(dtype, kString) && !IsSubType(dtype, kTensorType)) { + MS_LOG(EXCEPTION) << "Expect tensor type kNumber or kString or kTensor but got: " << dtype->ToString() << "."; + } + auto abs_sparse_tensor = std::make_shared(dtype, shape_); + + abs_sparse_tensor->set_indices(indices_->ToAbstract()->cast()); + abs_sparse_tensor->set_values(values_->ToAbstract()->cast()); + + std::vector abstract_shape; + std::transform( + shape_.begin(), shape_.end(), std::back_inserter(abstract_shape), + [](auto shp) -> abstract::AbstractScalarPtr { return std::make_shared(shp); }); + abs_sparse_tensor->set_dense_shape(std::make_shared(abstract_shape)); + + return abs_sparse_tensor; +} } // namespace tensor } // namespace mindspore diff --git a/mindspore/core/ir/tensor.h b/mindspore/core/ir/tensor.h index d60d89b93a91..24263d2a5f00 100644 --- a/mindspore/core/ir/tensor.h +++ b/mindspore/core/ir/tensor.h @@ -606,6 +606,57 @@ class MS_CORE_API CSRTensor : public MetaSparseTensor { TensorPtr values_; }; using CSRTensorPtr = std::shared_ptr; + +// COOTensor entity class +class MS_CORE_API COOTensor : public MetaSparseTensor { + public: + abstract::AbstractBasePtr ToAbstract() override; + + /// \brief Create COOTensor with given data type from another tensor. + /// + /// \param[in] indices [Tensor] The indices. + /// \param[in] values [Tensor] The values. + /// \param[in] shape The shape represented by ShapeVector of the COOTensor. + COOTensor(const TensorPtr indices, const TensorPtr values, const ShapeVector &shape) + : MetaSparseTensor(values->data_type(), shape), indices_(indices), values_(values) {} + + /// Destructor of COOTensor. + ~COOTensor() override = default; + + /// \brief Gets COOTensor's indices. + /// + /// \return [TensorPtr] The indices. + TensorPtr GetIndices() { return indices_; } + + /// \brief Gets COOTensor's values. + /// + /// \return [TensorPtr] The values. + TensorPtr GetValues() { return values_; } + + /// \brief Compare two tensor objects to see if they have same data type, shape and data address. + /// + /// \param[in] tensor The Tensor object to be compared. + /// \return True if having same type, shape and data address, otherwise false. + bool operator==(const COOTensor &sparse_tensor) const { return &sparse_tensor == this; } + + bool operator==(const Value &other) const override { + if (other.isa()) { + auto &other_ = static_cast(other); + return *this == other_; + } + return false; + } + + /// \brief Get display information of this Tensor. + /// + /// \return The display information of this Tensor. + std::string ToString() const override; + + private: + TensorPtr indices_; + TensorPtr values_; +}; +using COOTensorPtr = std::shared_ptr; } // namespace tensor } // namespace mindspore diff --git a/mindspore/core/mindapi/base/type_id.h b/mindspore/core/mindapi/base/type_id.h index 1b668eb61754..fd7fda666779 100644 --- a/mindspore/core/mindapi/base/type_id.h +++ b/mindspore/core/mindapi/base/type_id.h @@ -47,7 +47,7 @@ enum TypeId : int { kObjectTypeKeyword, kObjectTypeTensorType, kObjectTypeRowTensorType, - kObjectTypeSparseTensorType, + kObjectTypeCOOTensorType, kObjectTypeUndeterminedType, kObjectTypeClass, kObjectTypeDictionary, diff --git a/mindspore/lite/micro/example/mnist_stm32f746/mnist_stm32f746/include/ir/dtype/type_id.h b/mindspore/lite/micro/example/mnist_stm32f746/mnist_stm32f746/include/ir/dtype/type_id.h index 46209b8ba43e..5eadda2de32e 100755 --- a/mindspore/lite/micro/example/mnist_stm32f746/mnist_stm32f746/include/ir/dtype/type_id.h +++ b/mindspore/lite/micro/example/mnist_stm32f746/mnist_stm32f746/include/ir/dtype/type_id.h @@ -48,7 +48,7 @@ enum TypeId : int { kObjectTypeKeyword, kObjectTypeTensorType, kObjectTypeRowTensorType, - kObjectTypeSparseTensorType, + kObjectTypeCOOTensorType, kObjectTypeUndeterminedType, kObjectTypeClass, kObjectTypeDictionary, diff --git a/mindspore/python/mindspore/_extends/parse/resources.py b/mindspore/python/mindspore/_extends/parse/resources.py index 33bc91fd31a3..b381ec3e3921 100644 --- a/mindspore/python/mindspore/_extends/parse/resources.py +++ b/mindspore/python/mindspore/_extends/parse/resources.py @@ -18,7 +18,7 @@ import ast import math -from mindspore import RowTensor, SparseTensor, CSRTensor +from mindspore import RowTensor, SparseTensor, COOTensor, CSRTensor from mindspore.ops import functional as F, composite as C from mindspore.ops.composite import multitype_ops from mindspore._c_expression import security @@ -158,6 +158,7 @@ convert_object_map = { # user defined RowTensor: F.make_row_tensor, SparseTensor: F.make_sparse_tensor, + COOTensor: F.make_coo_tensor, CSRTensor: F.make_csr_tensor } diff --git a/mindspore/python/mindspore/common/__init__.py b/mindspore/python/mindspore/common/__init__.py index 689337e3a2f5..9c795336c2a4 100644 --- a/mindspore/python/mindspore/common/__init__.py +++ b/mindspore/python/mindspore/common/__init__.py @@ -24,7 +24,7 @@ from .dtype import Type, int8, byte, int16, short, int32, intc, int64, intp, \ from .dump import set_dump from .parameter import Parameter, ParameterTuple from .seed import set_seed, get_seed -from .tensor import Tensor, RowTensor, SparseTensor, CSRTensor +from .tensor import Tensor, RowTensor, SparseTensor, COOTensor, CSRTensor # symbols from dtype __all__ = [ @@ -53,7 +53,7 @@ __all__ = [ ] __all__.extend([ - "Tensor", "RowTensor", "SparseTensor", "CSRTensor", # tensor + "Tensor", "RowTensor", "SparseTensor", "COOTensor", "CSRTensor", # tensor 'ms_function', # api 'Parameter', 'ParameterTuple', # parameter "dtype", diff --git a/mindspore/python/mindspore/common/api.py b/mindspore/python/mindspore/common/api.py index eaee92cc0d69..ec85229b5873 100644 --- a/mindspore/python/mindspore/common/api.py +++ b/mindspore/python/mindspore/common/api.py @@ -29,7 +29,8 @@ from mindspore import log as logger from mindspore._extends.remote import kernel_build_server from .tensor import Tensor as MsTensor from .tensor import CSRTensor as MsCSRTensor -from .._c_expression import GraphExecutor_, Tensor, MetaTensor, CSRTensor, PynativeExecutor_, _ms_memory_recycle +from .tensor import COOTensor as MsCOOTensor +from .._c_expression import GraphExecutor_, Tensor, MetaTensor, CSRTensor, COOTensor, PynativeExecutor_ from .._c_expression import verify_inputs_signature, init_exec_dataset, _set_dataset_mode_config, init_pipeline from ..parallel._ps_context import _is_role_pserver, _is_role_sched from ..parallel._utils import _get_device_num, _get_global_rank, _need_to_full, _check_full_batch, _to_full_tensor, \ @@ -65,6 +66,8 @@ def _wrap_func(fn): return MsTensor(data) if isinstance(data, CSRTensor) and not isinstance(data, MsCSRTensor): return MsCSRTensor(csr_tensor=data) + if isinstance(data, COOTensor) and not isinstance(data, MsCOOTensor): + return MsCOOTensor(coo_tensor=data) if isinstance(data, tuple): return tuple(_convert_data(x) for x in data) if isinstance(data, list): diff --git a/mindspore/python/mindspore/common/dtype.py b/mindspore/python/mindspore/common/dtype.py index 971db62a541b..a7a05bcb671f 100644 --- a/mindspore/python/mindspore/common/dtype.py +++ b/mindspore/python/mindspore/common/dtype.py @@ -92,7 +92,7 @@ type_none = typing.TypeNone() tensor = typing.TensorType() index_slices = typing.RowTensorType() -sparse_tensor = typing.SparseTensorType() +coo_tensor = typing.COOTensorType() csr_tensor = typing.CSRTensorType() undetermined = typing.UndeterminedType() diff --git a/mindspore/python/mindspore/common/tensor.py b/mindspore/python/mindspore/common/tensor.py index 2e3a80e93b2f..46d91fbbf8a5 100644 --- a/mindspore/python/mindspore/common/tensor.py +++ b/mindspore/python/mindspore/common/tensor.py @@ -22,11 +22,12 @@ from . import dtype as mstype from ._register_for_tensor import tensor_operator_registry from .._c_expression import Tensor as Tensor_ from .._c_expression import CSRTensor as CSRTensor_ +from .._c_expression import COOTensor as COOTensor_ from .._c_expression import PynativeExecutor_ from .._checkparam import Validator as validator from .._checkparam import Rel -__all__ = ['Tensor', 'RowTensor', 'SparseTensor', 'CSRTensor'] +__all__ = ['Tensor', 'RowTensor', 'SparseTensor', 'COOTensor', 'CSRTensor'] np_types = (np.int8, np.int16, np.int32, np.int64, np.uint8, np.uint16, np.uint32, np.uint64, np.float16, np.float32, np.float64, np.bool_, np.complex64, np.complex128) @@ -2318,7 +2319,7 @@ class RowTensor: return self.__dense_shape -class SparseTensor: +class SparseTensor(COOTensor_): """ A sparse representation of a set of nonzero elements from a tensor at given indices. @@ -2337,7 +2338,8 @@ class SparseTensor: [0, 0, 0, 0]] Note: - SparseTensor is not supported in Pynative mode at the moment. + The interface is deprecated from version 1.7 and will be removed in a future version. + Please use 'COOTensor' instead. Args: indices (Tensor): A 2-D integer Tensor of shape `[N, ndims]`, @@ -2345,53 +2347,122 @@ class SparseTensor: the SparseTensor, respectively. values (Tensor): A 1-D tensor of any type and shape `[N]`, which supplies the values for each element in `indices`. - dense_shape (tuple(int)): A integer tuple of size `ndims`, - which specifies the dense_shape of the sparse tensor. + shape (tuple(int)): A integer tuple of size `ndims`, + which specifies the shape of the sparse tensor. Returns: - SparseTensor, composed of `indices`, `values`, and `dense_shape`. + SparseTensor, composed of `indices`, `values`, and `shape`. Examples: >>> import mindspore as ms >>> import mindspore.nn as nn >>> from mindspore import Tensor, SparseTensor - >>> class Net(nn.Cell): - ... def __init__(self, dense_shape): - ... super(Net, self).__init__() - ... self.dense_shape = dense_shape - ... def construct(self, indices, values): - ... x = SparseTensor(indices, values, self.dense_shape) - ... return x.values, x.indices, x.dense_shape - >>> >>> indices = Tensor([[0, 1], [1, 2]]) >>> values = Tensor([1, 2], dtype=ms.float32) - >>> out = Net((3, 4))(indices, values) - >>> print(out[0]) + >>> shape = (3, 4) + >>> x = SparseTensor(indices, values, shape) + >>> print(x.values) [1. 2.] - >>> print(out[1]) + >>> print(x.indices) [[0 1] [1 2]] - >>> print(out[2]) + >>> print(x.shape) (3, 4) """ - def __init__(self, indices, values, dense_shape): - "Init SparseTensor" - self.__indices = indices - self.__values = values - self.__dense_shape = dense_shape + def __init__(self, indices=None, values=None, shape=None, coo_tensor=None): + "Init COOTensor" + print("WARNING: 'SparseTensor' is deprecated from version 1.7 and will be removed in a future version. " + + "Please use 'COOTensor' instead.") + if indices is None and values is None and shape is None and coo_tensor is not None: + if not isinstance(coo_tensor, (COOTensor, COOTensor_)): + raise TypeError("If only one input provided, it must be a COOTensor.") + COOTensor_.__init__(self, coo_tensor) + else: + if not (isinstance(indices, Tensor) and isinstance(values, Tensor) and isinstance(shape, tuple)): + raise TypeError("Inputs must follow: COOTensor(indices, values, shape).") + COOTensor_.__init__(self, indices, values, shape) @property def indices(self): - return self.__indices + return Tensor(self._indices) @property def values(self): - return self.__values + return Tensor(self._values) @property - def dense_shape(self): - return self.__dense_shape + def shape(self): + return self._shape + + +class COOTensor(COOTensor_): + """ + A sparse representation of a set of nonzero elements from a tensor at given indices. + + For a tensor dense, its COOTensor(indices, values, dense_shape) has + `dense[indices[i]] = values[i]`. + + For example, if indices is [[0, 1], [1, 2]], values is [1, 2], dense_shape is + (3, 4), then the dense representation of the sparse tensor will be: + + .. code-block:: + + [[0, 1, 0, 0], + [0, 0, 2, 0], + [0, 0, 0, 0]] + + Args: + indices (Tensor): A 2-D integer Tensor of shape `[N, ndims]`, + where N and ndims are the number of `values` and number of dimensions in + the COOTensor, respectively. + values (Tensor): A 1-D tensor of any type and shape `[N]`, which + supplies the values for each element in `indices`. + shape (tuple(int)): A integer tuple of size `ndims`, + which specifies the dense_shape of the sparse tensor. + + Returns: + COOTensor, composed of `indices`, `values`, and `shape`. + + Examples: + >>> import mindspore as ms + >>> import mindspore.nn as nn + >>> from mindspore import Tensor, COOTensor + >>> indices = Tensor([[0, 1], [1, 2]]) + >>> values = Tensor([1, 2], dtype=ms.float32) + >>> shape = (3, 4) + >>> x = COOTensor(indices, values, shape) + >>> print(x.values) + [1. 2.] + >>> print(x.indices) + [[0 1] + [1 2]] + >>> print(x.shape) + (3, 4) + """ + + def __init__(self, indices=None, values=None, shape=None, coo_tensor=None): + "Init COOTensor" + if indices is None and values is None and shape is None and coo_tensor is not None: + if not isinstance(coo_tensor, (COOTensor, COOTensor_)): + raise TypeError("If only one input provided, it must be a COOTensor.") + COOTensor_.__init__(self, coo_tensor) + else: + if not (isinstance(indices, Tensor) and isinstance(values, Tensor) and isinstance(shape, tuple)): + raise TypeError("Inputs must follow: COOTensor(indices, values, shape).") + COOTensor_.__init__(self, indices, values, shape) + + @property + def indices(self): + return Tensor(self._indices) + + @property + def values(self): + return Tensor(self._values) + + @property + def shape(self): + return self._shape class CSRTensor(CSRTensor_): diff --git a/mindspore/python/mindspore/nn/sparse/sparse.py b/mindspore/python/mindspore/nn/sparse/sparse.py index 671136ccbb64..f505dfad5b58 100644 --- a/mindspore/python/mindspore/nn/sparse/sparse.py +++ b/mindspore/python/mindspore/nn/sparse/sparse.py @@ -19,7 +19,7 @@ from ..cell import Cell class SparseToDense(Cell): """ - Converts a sparse tensor into dense. + Converts a sparse tensor(COOTensor) into dense. In Python, for the ease of use, three tensors are collected into a SparseTensor class. MindSpore uses three independent dense tensors: indices, value and dense shape to represent the sparse tensor. @@ -27,7 +27,7 @@ class SparseToDense(Cell): before being passed to the OPS below. Inputs: - - **sparse_tensor** (:class:`mindspore.SparseTensor`): the sparse tensor to convert. + - **coo_tensor** (:class:`mindspore.COOTensor`): the sparse COOTensor to convert. Outputs: Tensor, converted from sparse tensor. @@ -35,24 +35,31 @@ class SparseToDense(Cell): Raises: TypeError: If `sparse_tensor.indices` is not a Tensor. TypeError: If `sparse_tensor.values` is not a Tensor. - TypeError: If `sparse_tensor.dense_shape` is not a tuple. + TypeError: If `sparse_tensor.shape` is not a tuple. Supported Platforms: ``CPU`` Examples: >>> import mindspore as ms - >>> from mindspore import Tensor, SparseTensor + >>> from mindspore import Tensor, COOTensor >>> import mindspore.nn as nn >>> import mindspore.context as context >>> context.set_context(mode=context.PYNATIVE_MODE) >>> indices = Tensor([[0, 1], [1, 2]]) >>> values = Tensor([1, 2], dtype=ms.int32) >>> dense_shape = (3, 4) - >>> sparse_tensor = SparseTensor(indices, values, dense_shape) - >>> sparse_to_dense = nn.SparseToDense() - >>> result = sparse_to_dense(sparse_tensor) - >>> print(result) + >>> class Net(nn.Cell): + ... def __init__(self, dense_shape): + ... super(Net, self).__init__() + ... self.dense_shape = dense_shape + ... self.op = nn.SparseToDense() + ... + ... def construct(self, indices, values): + ... x = COOTensor(indices, values, self.dense_shape) + ... return self.op(x) + ... + >>> print(Net(dense_shape)(indices, values)) [[0 1 0 0] [0 0 2 0] [0 0 0 0]] @@ -66,7 +73,7 @@ class SparseToDense(Cell): def construct(self, sparse_tensor): return self.sparse_to_dense(sparse_tensor.indices, sparse_tensor.values, - sparse_tensor.dense_shape) + sparse_tensor.shape) class SparseTensorDenseMatmul(Cell): diff --git a/mindspore/python/mindspore/ops/_grad/grad_sparse.py b/mindspore/python/mindspore/ops/_grad/grad_sparse.py index aacc9f3fa55a..48c36f252fd9 100644 --- a/mindspore/python/mindspore/ops/_grad/grad_sparse.py +++ b/mindspore/python/mindspore/ops/_grad/grad_sparse.py @@ -23,29 +23,29 @@ from .grad_base import bprops, bprop_getters # Unused parameters are placeholders. -@bprops.register("MakeSparseTensor") -def bprop_make_sparse_tensor(indices, values, dense_shape, out, dout): - """Backpropagator for primitive `MakeSparseTensor`.""" - return zeros_like(indices), F.sparse_tensor_get_values(dout), () +@bprops.register("MakeCOOTensor") +def bprop_make_coo_tensor(indices, values, dense_shape, out, dout): + """Backpropagator for primitive `MakeCOOTensor`.""" + return zeros_like(indices), F.coo_tensor_get_values(dout), () -@bprops.register("SparseTensorGetIndices") +@bprops.register("COOTensorGetIndices") def bprop_sparse_tensor_get_indices(sparse_tensor, out, dout): - """Backpropagator for primitive `SparseTensorGetIndices`.""" + """Backpropagator for primitive `COOTensorGetIndices`.""" return (zeros_like(sparse_tensor),) -@bprops.register("SparseTensorGetValues") +@bprops.register("COOTensorGetValues") def bprop_sparse_tensor_get_values(sparse_tensor, out, dout): - """Backpropagator for primitive `SparseTensorGetValues`.""" - return F.make_sparse_tensor(F.sparse_tensor_get_indices(sparse_tensor), - dout, - F.sparse_tensor_get_dense_shape(sparse_tensor)) + """Backpropagator for primitive `COOTensorGetValues`.""" + return F.make_coo_tensor(F.coo_tensor_get_indices(sparse_tensor), + dout, + F.coo_tensor_get_dense_shape(sparse_tensor)) -@bprops.register("SparseTensorGetDenseShape") +@bprops.register("COOTensorrGetDenseShape") def bprop_sparse_tensor_get_dense_shape(sparse_tensor, out, dout): - """Backpropagator for primitive `SparseTensorGetDenseShape`.""" + """Backpropagator for primitive `COOTensorGetDenseShape`.""" return (zeros_like(sparse_tensor),) diff --git a/mindspore/python/mindspore/ops/composite/multitype_ops/ones_like_impl.py b/mindspore/python/mindspore/ops/composite/multitype_ops/ones_like_impl.py index 27bad0e3d895..bd46bc729d96 100644 --- a/mindspore/python/mindspore/ops/composite/multitype_ops/ones_like_impl.py +++ b/mindspore/python/mindspore/ops/composite/multitype_ops/ones_like_impl.py @@ -48,14 +48,14 @@ def _ones_like_tensor(x): return P.Fill()(P.DType()(x), P.Shape()(x), 1.0) -@ones_like_leaf.register("SparseTensor") -def _ones_like_sparse_tensor(x): +@ones_like_leaf.register("COOTensor") +def _ones_like_coo_tensor(x): """Returns a tensor with the same shape and dtype as x and all elements are 1.""" - values_ = F.sparse_tensor_get_values(x) + values_ = F.coo_tensor_get_values(x) values = P.Fill()(P.DType()(values_), P.Shape()(values_), 1.0) - return F.make_sparse_tensor(F.sparse_tensor_get_indices(x), values, F.sparse_tensor_get_dense_shape(x)) + return F.make_coo_tensor(F.coo_tensor_get_indices(x), values, F.coo_tensor_get_dense_shape(x)) @ones_like_leaf.register("Function") diff --git a/mindspore/python/mindspore/ops/functional.py b/mindspore/python/mindspore/ops/functional.py index 9b943919d25f..243d5215902e 100644 --- a/mindspore/python/mindspore/ops/functional.py +++ b/mindspore/python/mindspore/ops/functional.py @@ -601,10 +601,17 @@ row_tensor_get_indices = Primitive('RowTensorGetIndices') row_tensor_get_dense_shape = Primitive('RowTensorGetDenseShape') row_tensor_add = Primitive('RowTensorAdd') -make_sparse_tensor = Primitive('MakeSparseTensor') -sparse_tensor_get_values = Primitive('SparseTensorGetValues') -sparse_tensor_get_indices = Primitive('SparseTensorGetIndices') -sparse_tensor_get_dense_shape = Primitive('SparseTensorGetDenseShape') +make_coo_tensor = Primitive('MakeCOOTensor') +coo_tensor_get_values = Primitive('COOTensorGetValues') +coo_tensor_get_indices = Primitive('COOTensorGetIndices') +coo_tensor_get_dense_shape = Primitive('COOTensorGetDenseShape') + +def make_sparse_tensor(indices, values, dense_shape): + """Call make_coo_tensor in this function.""" + print("WARNING: 'SparseTensor' is deprecated from version 1.7 and will be removed in a future version. " + + "Please use 'COOTensor' instead.") + return make_coo_tensor(indices, values, dense_shape) + make_csr_tensor = Primitive('MakeCSRTensor') csr_tensor_get_values = Primitive('CSRTensorGetValues') diff --git a/tests/st/sparse/test_coo.py b/tests/st/sparse/test_coo.py new file mode 100644 index 000000000000..4c24549aa8d2 --- /dev/null +++ b/tests/st/sparse/test_coo.py @@ -0,0 +1,93 @@ +# Copyright 2022 Huawei Technologies Co., Ltd +# +# 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. +# ============================================================================ +"""smoke tests for COO operations""" + +import pytest +import numpy as np + +from mindspore import Tensor, COOTensor, ms_function, nn, context +from mindspore.common import dtype as mstype + + +context.set_context(mode=context.GRAPH_MODE) + + +def compare_coo(coo1, coo2): + assert isinstance(coo1, COOTensor) + assert isinstance(coo2, COOTensor) + assert (coo1.indices.asnumpy() == coo2.indices.asnumpy()).all() + assert (coo1.values.asnumpy() == coo2.values.asnumpy()).all() + assert coo1.shape == coo2.shape + + +@pytest.mark.level0 +@pytest.mark.platform_arm_ascend_training +@pytest.mark.platform_x86_ascend_training +@pytest.mark.platform_x86_gpu_training +@pytest.mark.env_onecard +def test_make_coo(): + """ + Feature: Test COOTensor Constructor in Graph and PyNative. + Description: Test COOTensor(indices, values, shape) and COOTensor(COOTensor) + Expectation: Success. + """ + indices = Tensor([[0, 1], [1, 2]]) + values = Tensor([1, 2], dtype=mstype.float32) + dense_shape = (3, 4) + + def test_pynative(): + return COOTensor(indices, values, dense_shape) + test_graph = ms_function(test_pynative) + + coo1 = test_pynative() + coo2 = test_graph() + compare_coo(coo1, coo2) + coo3 = COOTensor(coo_tensor=coo2) + compare_coo(coo3, coo2) + + +@pytest.mark.level0 +@pytest.mark.platform_arm_ascend_training +@pytest.mark.platform_x86_ascend_training +@pytest.mark.platform_x86_gpu_training +@pytest.mark.env_onecard +def test_coo_tensor_in_while(): + """ + Feature: Test COOTensor in while loop. + Description: Test COOTensor computation in while loop. + Expectation: Success. + """ + class COOTensorWithControlWhile(nn.Cell): + def __init__(self, shape): + super().__init__() + self.shape = shape + + @ms_function + def construct(self, a, b, indices, values): + x = COOTensor(indices, values, self.shape) + while a > b: + x = COOTensor(indices, values, self.shape) + b = b + 1 + return x + a = Tensor(3, mstype.int32) + b = Tensor(0, mstype.int32) + indices = Tensor([[0, 1], [1, 2]]) + values = Tensor([1, 2], dtype=mstype.float32) + shape = (3, 4) + net = COOTensorWithControlWhile(shape) + out = net(a, b, indices, values) + assert np.allclose(out.indices.asnumpy(), indices.asnumpy(), .0, .0) + assert np.allclose(out.values.asnumpy(), values.asnumpy(), .0, .0) + assert out.shape == shape diff --git a/tests/st/sparse/test_csr.py b/tests/st/sparse/test_csr.py index f62fc4536a77..a236147a8a1e 100644 --- a/tests/st/sparse/test_csr.py +++ b/tests/st/sparse/test_csr.py @@ -270,7 +270,7 @@ def test_csr_ops(): @pytest.mark.platform_x86_gpu_training @pytest.mark.platform_x86_cpu @pytest.mark.env_onecard -def test_csrtensor_export_mindir(): +def test_csrtensor_export_and_import_mindir(): """ Feature: Test exporting and loading CSRTensor MindIR. Description: Test export and load. @@ -308,7 +308,7 @@ def test_csrtensor_export_mindir(): @pytest.mark.level0 @pytest.mark.platform_x86_gpu_training @pytest.mark.env_onecard -def test_csrops_export_mindir(): +def test_csrops_export_and_import_mindir(): """ Feature: Test exporting and loading CSRTensor MindIR in a net. Description: Test export and load. diff --git a/tests/ut/cpp/python_input/gtest_input/optimizer/opt_test.py b/tests/ut/cpp/python_input/gtest_input/optimizer/opt_test.py index e91f01da3364..7bdea4799899 100644 --- a/tests/ut/cpp/python_input/gtest_input/optimizer/opt_test.py +++ b/tests/ut/cpp/python_input/gtest_input/optimizer/opt_test.py @@ -1173,10 +1173,10 @@ def test_row_tensor(tag): def test_sparse_tensor(tag): """ test_add_zero """ fns = FnDict() - make_sparse_tensor = Primitive('MakeSparseTensor') - sparse_tensor_get_values = Primitive('SparseTensorGetValues') - sparse_tensor_get_indices = Primitive('SparseTensorGetIndices') - sparse_tensor_get_dense_shape = Primitive('SparseTensorGetDenseShape') + make_sparse_tensor = Primitive('MakeCOOTensor') + sparse_tensor_get_values = Primitive('COOTensorGetValues') + sparse_tensor_get_indices = Primitive('COOTensorGetIndices') + sparse_tensor_get_dense_shape = Primitive('COOTensorGetDenseShape') @fns def before_get_indices(x, y, z): diff --git a/tests/ut/python/ir/test_sparse_tensor.py b/tests/ut/python/ir/test_sparse_tensor.py index bd84640ec209..0ccd530ee282 100644 --- a/tests/ut/python/ir/test_sparse_tensor.py +++ b/tests/ut/python/ir/test_sparse_tensor.py @@ -24,7 +24,7 @@ import pytest import mindspore as ms import mindspore.nn as nn from mindspore.ops import composite as C -from mindspore import Tensor, SparseTensor, context +from mindspore import Tensor, COOTensor, context @pytest.fixture(scope="module", autouse=True) def setup_teardown(): @@ -40,24 +40,34 @@ class MakeSparseTensor(nn.Cell): super(MakeSparseTensor, self).__init__() self.dense_shape = dense_shape def construct(self, indices, values): - ret = (SparseTensor(indices, values, self.dense_shape),) + ret = (COOTensor(indices, values, self.dense_shape),) return ret[0] -def test_sparse_tensor_make_sparse_tensor(): +def test_sparse_tensor_make_coo_tensor(): + """ + Feature: Test MakeCOOTensor. + Description: Test MakeCOOTensor. + Expectation: Success. + """ indices = Tensor([[0, 1], [1, 2]]) values = Tensor([1, 2], dtype=ms.float32) MakeSparseTensor((3, 4))(indices, values) def test_sparse_tensor_attr(): + """ + Feature: Test GetAttr. + Description: Test GetAttr in COOTensor (values, indices, dense_shape). + Expectation: Success. + """ class SparseTensorGetAttr(nn.Cell): def __init__(self): super(SparseTensorGetAttr, self).__init__() self.dense_shape = (3, 4) def construct(self, indices, values): - x = SparseTensor(indices, values, self.dense_shape) - return x.values, x.indices, x.dense_shape + x = COOTensor(indices, values, self.dense_shape) + return x.values, x.indices, x.shape indices = Tensor([[0, 1], [1, 2]]) values = Tensor([1, 2], dtype=ms.float32) @@ -66,6 +76,11 @@ def test_sparse_tensor_attr(): def test_sparse_tensor_indices_dim_greater_than_dense_shape_dim(): + """ + Feature: Test MakeSparseTensor. + Description: Test sparse tensor indices dim greater than dense shape dim. + Expectation: Success. + """ indices = Tensor(np.array([[0, 0, 0], [0, 0, 1]], dtype=np.int32)) values = Tensor(np.array([100, 200], dtype=np.float32)) dense_shape = (2, 2) @@ -74,6 +89,11 @@ def test_sparse_tensor_indices_dim_greater_than_dense_shape_dim(): def test_sparse_tensor_indices_dim_less_than_dense_shape_dim(): + """ + Feature: Test MakeSparseTensor. + Description: Test sparse tensor indices dim less than dense shape dim. + Expectation: Success. + """ indices = Tensor(np.array([[0, 0], [0, 1]], dtype=np.int32)) values = Tensor(np.array([100, 200], dtype=np.float32)) dense_shape = (2, 2, 2) @@ -82,13 +102,18 @@ def test_sparse_tensor_indices_dim_less_than_dense_shape_dim(): def test_sparse_tensor_to_tensor(): + """ + Feature: Test nn.SparseToDense. + Description: Test COOTensor to dense tensor. + Expectation: Success. + """ class SparseToDenseCell(nn.Cell): def __init__(self, dense_shape): super(SparseToDenseCell, self).__init__() self.dense_shape = dense_shape self.sparse_to_dense = nn.SparseToDense() def construct(self, indices, values): - sparse = SparseTensor(indices, values, self.dense_shape) + sparse = COOTensor(indices, values, self.dense_shape) return self.sparse_to_dense(sparse) indices = Tensor([[0, 1], [1, 2]]) diff --git a/tests/ut/python/pynative_mode/test_sparse_pynative.py b/tests/ut/python/pynative_mode/test_sparse_pynative.py index 488bc12965ab..cebf70d1ddd0 100644 --- a/tests/ut/python/pynative_mode/test_sparse_pynative.py +++ b/tests/ut/python/pynative_mode/test_sparse_pynative.py @@ -21,7 +21,7 @@ import pytest import mindspore as ms import mindspore.nn as nn -from mindspore import context, Tensor, RowTensor, SparseTensor +from mindspore import context, Tensor, RowTensor, COOTensor from mindspore.ops import composite as C @pytest.fixture(scope="module", autouse=True) @@ -42,6 +42,11 @@ class GradWrap(nn.Cell): def test_row_tensor_attr(): + """ + Feature: Test RowTensor. + Description: Test RowTensor GetAttr. + Expectation: Success. + """ class RowTensorGetAttr(nn.Cell): def __init__(self, dense_shape): super(RowTensorGetAttr, self).__init__() @@ -56,13 +61,18 @@ def test_row_tensor_attr(): def test_sparse_tensor_attr(): + """ + Feature: Test COOTensor. + Description: Test COOTensor GetAttr. + Expectation: Success. + """ class SparseTensorGetAttr(nn.Cell): def __init__(self): super(SparseTensorGetAttr, self).__init__() self.dense_shape = (3, 4) def construct(self, indices, values): - x = SparseTensor(indices, values, self.dense_shape) - return x.values, x.indices, x.dense_shape + x = COOTensor(indices, values, self.dense_shape) + return x.values, x.indices, x.shape indices = Tensor([[0, 1], [1, 2]]) values = Tensor([1, 2], dtype=ms.float32) -- Gitee