From e234019ad7abe266e6481fbafeac6d626960223a Mon Sep 17 00:00:00 2001 From: iku50 Date: Tue, 3 Oct 2023 13:03:17 +0800 Subject: [PATCH 1/3] ok --- mindspore/core/abstract/abstract_function.cc | 122 +++++++- mindspore/core/abstract/abstract_function.h | 41 +++ mindspore/core/abstract/analysis_context.cc | 89 +++++- mindspore/core/abstract/analysis_context.h | 66 ++++- mindspore/core/abstract/dshape.cc | 21 +- mindspore/core/abstract/param_validator.cc | 33 ++- mindspore/core/abstract/param_validator.h | 66 ++++- mindspore/core/abstract/prim_maths.cc | 273 ++++++------------ .../core/abstract/primitive_infer_map.cc | 37 ++- mindspore/core/abstract/primitive_infer_map.h | 32 +- mindspore/core/abstract/utils.cc | 73 +++-- mindspore/core/abstract/utils.h | 82 +++++- 12 files changed, 671 insertions(+), 264 deletions(-) diff --git a/mindspore/core/abstract/abstract_function.cc b/mindspore/core/abstract/abstract_function.cc index ca8dff5e5a3..3d05feac83c 100644 --- a/mindspore/core/abstract/abstract_function.cc +++ b/mindspore/core/abstract/abstract_function.cc @@ -23,80 +23,124 @@ namespace mindspore { namespace abstract { class Evaluator; class AnalysisEngine; +// Function to create an AbstractFunction from a list of AbstractFuncAtomPtr. AbstractFunctionPtr AbstractFunction::MakeAbstractFunction(const AbstractFuncAtomPtrList &func_list) { + // Check the size of the input list. if (func_list.size() == 1) { + // If there is only one element in the list, return that element. return func_list[0]; } + // If there are multiple elements in the list, create an AbstractFuncUnion. return std::make_shared(func_list); } +// Join two AbstractFunctions into a single AbstractFunction. AbstractFunctionPtr AbstractFuncAtom::Join(const AbstractFunctionPtr &other) { + // Check if the 'other' AbstractFunction pointer is not null. MS_EXCEPTION_IF_NULL(other); + + // Get a shared pointer to the current AbstractFuncAtom. auto this_func = shared_from_base(); + if (other->isa()) { + // If 'other' is an AbstractFuncAtom, check if the two AbstractFuncAtoms are equal. if (*this_func == *other) { + // If they are equal, return the current AbstractFuncAtom. return this_func; } + // If they are not equal, create an AbstractFuncUnion with both AbstractFuncAtoms. return std::make_shared(this_func, other); } + + // If 'other' is an AbstractFuncUnion, check if it is a superset of the current AbstractFuncAtom. auto other_union = dyn_cast(other); MS_EXCEPTION_IF_NULL(other_union); + if (other_union->IsSuperSet(this_func)) { + // If 'other_union' is a superset of the current AbstractFuncAtom, return 'other'. return other; } + + // If 'other_union' is not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } +// Visit function to perform an operation on the current AbstractFuncAtom. void AbstractFuncAtom::Visit(std::function visit_func) const { + // Call the 'visit_func' function with the current AbstractFuncAtom. visit_func(const_cast(this)->shared_from_base()); } -bool AbstractFuncAtom::operator==(const AbstractFunction &other) const { return this == &other; } +// Equality comparison operator for AbstractFunction. +bool AbstractFuncAtom::operator==(const AbstractFunction &other) const { + // Check if the current AbstractFunction is equal to 'other' by comparing their addresses. + return this == &other; +} -AbstractFuncUnion::AbstractFuncUnion(const AbstractFuncAtomPtrList &func_list) { func_list_ = func_list; } +// Constructor for AbstractFuncUnion with a list of AbstractFuncAtom pointers. +AbstractFuncUnion::AbstractFuncUnion(const AbstractFuncAtomPtrList &func_list) { + func_list_ = func_list; +} +// Constructor for AbstractFuncUnion with two AbstractFunctions. AbstractFuncUnion::AbstractFuncUnion(const AbstractFunctionPtr &first, const AbstractFunctionPtr &second) { AbstractFuncAtomPtrList new_func_list; - auto build_func_list = [&new_func_list](const AbstractFuncAtomPtr &func) { new_func_list.push_back(func); }; + auto build_func_list = [&new_func_list](const AbstractFuncAtomPtr &func) { + new_func_list.push_back(func); + }; + + // Check if the input AbstractFunctions are not null. MS_EXCEPTION_IF_NULL(first); MS_EXCEPTION_IF_NULL(second); + + // Visit both AbstractFunctions and build the list. first->Visit(build_func_list); second->Visit(build_func_list); + func_list_ = new_func_list; } +// Convert AbstractFuncUnion to a string. std::string AbstractFuncUnion::ToString() const { std::ostringstream buffer; buffer << "AbstractFuncUnion({"; int64_t i = 0; + for (const auto &func : func_list_) { MS_EXCEPTION_IF_NULL(func); buffer << "[" << i << "]: " << func->ToString() << ", "; i++; } + buffer << "})"; return buffer.str(); } +// Convert AbstractFuncUnion to a string, optionally in a verbose mode. std::string AbstractFuncUnion::ToString(bool verbose) const { if (verbose) { return ToString(); } + std::ostringstream buffer; buffer << type_name() << "({"; size_t i = 0; + for (const auto &func : func_list_) { MS_EXCEPTION_IF_NULL(func); buffer << func->ToString(false); i++; + if (i < func_list_.size()) { buffer << ", "; } } + buffer << "})"; return buffer.str(); } +// Check if the current AbstractFuncUnion is a superset of another AbstractFunction. bool AbstractFuncUnion::IsSuperSet(const AbstractFunctionPtr &other) { MS_EXCEPTION_IF_NULL(other); std::vector is_in_list; @@ -107,61 +151,90 @@ bool AbstractFuncUnion::IsSuperSet(const AbstractFunctionPtr &other) { } return true; }; + + // Visit 'other' AbstractFunction and build a list of whether each element is in the current AbstractFuncUnion. other->Visit(build_in_list); + + // Check if all elements in the 'is_in_list' are true. return std::all_of(is_in_list.begin(), is_in_list.end(), [](bool is_in) { return is_in; }); } +// Join two AbstractFunctions into a single AbstractFunction. AbstractFunctionPtr AbstractFuncUnion::Join(const AbstractFunctionPtr &other) { + // Get a shared pointer to the current AbstractFunction. auto this_func = shared_from_base(); MS_EXCEPTION_IF_NULL(other); + if (other->isa()) { + // If 'other' is an AbstractFuncAtom, check if the current AbstractFuncUnion is a superset of 'other'. if (IsSuperSet(other)) { + // If it is a superset, return the current AbstractFunction. return this_func; } + // If not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } + + // If 'other' is an AbstractFuncUnion, check if it is a superset of the current AbstractFunction. auto other_union = dyn_cast(other); MS_EXCEPTION_IF_NULL(other_union); + if (other_union->IsSuperSet(this_func)) { + // If it is a superset, return 'other'. return other; } + + // If not a superset, create an AbstractFuncUnion with both AbstractFunctions. return std::make_shared(this_func, other); } +// Visit function to perform an operation on each element of the AbstractFuncUnion. void AbstractFuncUnion::Visit(std::function visit_func) const { for (const AbstractFuncAtomPtr &poss : func_list_) { visit_func(poss); } } +// Equality comparison operator for AbstractFunction. bool AbstractFuncUnion::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } + auto other_union = static_cast(&other); + if (func_list_.size() != other_union->func_list_.size()) { return false; } + + // Check if the func_list_ vectors are equal. return func_list_ == other_union->func_list_; } +// Hash function for AbstractFuncUnion. std::size_t AbstractFuncUnion::hash() const { std::size_t hash_sum = 0; + for (const auto &f : func_list_) { MS_EXCEPTION_IF_NULL(f); hash_sum = hash_combine(hash_sum, f->hash()); } + return hash_sum; } +// Equality comparison operator for PrimitiveAbstractClosure. bool PrimitiveAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } + const auto &other_abs = static_cast(other); + // Check if both 'prim_' and 'tracking_id()' are equal. return (prim_ == other_abs.prim_) && (tracking_id() == other_abs.tracking_id()); } +// Hash function for PrimitiveAbstractClosure. std::size_t PrimitiveAbstractClosure::hash() const { // Keep in sync with operator==() which compares tid, prim_ & tracking_id; auto hash_value = static_cast(tid()); @@ -170,6 +243,7 @@ std::size_t PrimitiveAbstractClosure::hash() const { return hash_value; } +// Convert PrimitiveAbstractClosure to a string. std::string PrimitiveAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -177,15 +251,18 @@ std::string PrimitiveAbstractClosure::ToString(bool verbose) const { return type_name() + " (" + prim_->name() + ")"; } +// Equality comparison operator for FuncGraphAbstractClosure. bool FuncGraphAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_fg = static_cast(&other); + // Check if 'func_graph_', 'context_', and 'tracking_id()' are equal. return func_graph_ == other_fg->func_graph_ && context_ == other_fg->context_ && tracking_id() == other_fg->tracking_id(); } +// Hash function for FuncGraphAbstractClosure. std::size_t FuncGraphAbstractClosure::hash() const { auto hash_value = hash_combine(tid(), func_graph_->hash()); hash_value = hash_combine(hash_value, context_->hash()); @@ -195,6 +272,7 @@ std::size_t FuncGraphAbstractClosure::hash() const { return hash_value; } +// Convert FuncGraphAbstractClosure to a string. std::string FuncGraphAbstractClosure::ToString() const { std::stringstream ss; MS_EXCEPTION_IF_NULL(func_graph_); @@ -204,6 +282,7 @@ std::string FuncGraphAbstractClosure::ToString() const { return ss.str(); } +// Convert FuncGraphAbstractClosure to a string, optionally in a verbose mode. std::string FuncGraphAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -214,14 +293,17 @@ std::string FuncGraphAbstractClosure::ToString(bool verbose) const { return ss.str(); } +// Equality comparison operator for MetaFuncGraphAbstractClosure. bool MetaFuncGraphAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_meta_fg = static_cast(&other); + // Check if 'meta_func_graph_' and 'tracking_id()' are equal. return meta_func_graph_ == other_meta_fg->meta_func_graph_ && tracking_id() == other_meta_fg->tracking_id(); } +// Hash function for MetaFuncGraphAbstractClosure. std::size_t MetaFuncGraphAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(meta_func_graph_); auto hash_value = hash_combine(tid(), meta_func_graph_->hash()); @@ -231,16 +313,19 @@ std::size_t MetaFuncGraphAbstractClosure::hash() const { return hash_value; } +// Convert MetaFuncGraphAbstractClosure to a string. std::string MetaFuncGraphAbstractClosure::ToString() const { MS_EXCEPTION_IF_NULL(meta_func_graph_); return "MetaFuncGraphAbstractClosure: " + meta_func_graph_->name(); } +// Equality comparison operator for PartialAbstractClosure. bool PartialAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_partial = static_cast(&other); + // Check if 'fn_' and 'args_spec_list_' are equal. if (fn_ != other_partial->fn_) { return false; } @@ -250,6 +335,7 @@ bool PartialAbstractClosure::operator==(const AbstractFunction &other) const { return args_spec_list_ == other_partial->args_spec_list_; } +// Hash function for PartialAbstractClosure. std::size_t PartialAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); @@ -257,6 +343,7 @@ std::size_t PartialAbstractClosure::hash() const { return hash_value; } +// Convert PartialAbstractClosure to a string. std::string PartialAbstractClosure::ToString() const { std::ostringstream buffer; buffer << "PartialAbstractClosure(" << fn_->ToString() << "("; @@ -274,6 +361,7 @@ std::string PartialAbstractClosure::ToString() const { return buffer.str(); } +// Convert PartialAbstractClosure to a string, optionally in a verbose mode. std::string PartialAbstractClosure::ToString(bool verbose) const { if (verbose) { return ToString(); @@ -283,57 +371,69 @@ std::string PartialAbstractClosure::ToString(bool verbose) const { return buffer.str(); } +// Equality comparison operator for JTransformedAbstractClosure. bool JTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for JTransformedAbstractClosure. std::size_t JTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for TaylorTransformedAbstractClosure. bool TaylorTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for TaylorTransformedAbstractClosure. std::size_t TaylorTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for ShardTransformedAbstractClosure. bool ShardTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_' is equal. return fn_ == other_transformed->fn_; } +// Hash function for ShardTransformedAbstractClosure. std::size_t ShardTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); auto hash_value = hash_combine(tid(), fn_->hash()); return hash_value; } +// Equality comparison operator for VmapTransformedAbstractClosure. bool VmapTransformedAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_transformed = static_cast(&other); + // Check if 'fn_', 'in_axes_', and 'out_axes_' are equal. return fn_ == other_transformed->fn_ && in_axes_ == other_transformed->in_axes_ && out_axes_ == other_transformed->out_axes_; } +// Hash function for VmapTransformedAbstractClosure. std::size_t VmapTransformedAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(fn_); MS_EXCEPTION_IF_NULL(in_axes_); @@ -342,11 +442,13 @@ std::size_t VmapTransformedAbstractClosure::hash() const { return hash_value; } +// Equality comparison operator for VirtualAbstractClosure. bool VirtualAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_virtual = static_cast(&other); + // Check if 'output_' and 'args_spec_list_' are equal. if (output_ != other_virtual->output_) { return false; } @@ -356,6 +458,7 @@ bool VirtualAbstractClosure::operator==(const AbstractFunction &other) const { return args_spec_list_ == other_virtual->args_spec_list_; } +// Hash function for VirtualAbstractClosure. std::size_t VirtualAbstractClosure::hash() const { MS_EXCEPTION_IF_NULL(output_); auto hash_value = hash_combine(tid(), output_->hash()); @@ -363,6 +466,7 @@ std::size_t VirtualAbstractClosure::hash() const { return hash_value; } +// Convert VirtualAbstractClosure to a string. std::string VirtualAbstractClosure::ToString() const { std::ostringstream buffer; buffer << "VirtualAbstractClosure(args: {"; @@ -383,11 +487,13 @@ std::string VirtualAbstractClosure::ToString() const { return buffer.str(); } +// Equality comparison operator for TypedPrimitiveAbstractClosure. bool TypedPrimitiveAbstractClosure::operator==(const AbstractFunction &other) const { if (!other.isa()) { return false; } auto other_typed = static_cast(&other); + // Check if 'output_', 'prim_', and 'args_spec_list_' are equal. if (output_ != other_typed->output_) { return false; } @@ -400,15 +506,20 @@ bool TypedPrimitiveAbstractClosure::operator==(const AbstractFunction &other) co return args_spec_list_ == other_typed->args_spec_list_; } +// Hash function for TypedPrimitiveAbstractClosure. std::size_t TypedPrimitiveAbstractClosure::hash() const { - auto hash_value = hash_combine(tid(), prim_->hash()); + MS_EXCEPTION_IF_NULL(output_); + MS_EXCEPTION_IF_NULL(prim_); + auto hash_value = hash_combine(tid(), output_->hash()); + hash_value = hash_combine(hash_value, PointerHash{}(prim_)); hash_value = hash_combine(hash_value, AbstractBasePtrListHash(args_spec_list_)); return hash_value; } +// Convert TypedPrimitiveAbstractClosure to a string. std::string TypedPrimitiveAbstractClosure::ToString() const { std::ostringstream buffer; - buffer << "TypedPrimitiveAbstractClosure: primitive: " << prim_->name() << "(args: {"; + buffer << "TypedPrimitiveAbstractClosure(args: {"; int64_t i = 0; for (const auto &arg : args_spec_list_) { MS_EXCEPTION_IF_NULL(arg); @@ -425,5 +536,6 @@ std::string TypedPrimitiveAbstractClosure::ToString() const { buffer << "}, output: " << output_->ToString() << ")"; return buffer.str(); } + } // namespace abstract } // namespace mindspore diff --git a/mindspore/core/abstract/abstract_function.h b/mindspore/core/abstract/abstract_function.h index 917cb23876d..c2246665cb2 100644 --- a/mindspore/core/abstract/abstract_function.h +++ b/mindspore/core/abstract/abstract_function.h @@ -38,14 +38,25 @@ class MS_CORE_API AbstractFuncAtom : public AbstractFunction { ~AbstractFuncAtom() override = default; MS_DECLARE_PARENT(AbstractFuncAtom, AbstractFunction) + /// Override the GetUnique function to return a shared pointer to the current instance. AbstractFunctionPtr GetUnique() override { return shared_from_base(); } + /// Override the Join function to merge two instances of AbstractFunction. + /// \param[in] other: Another instance of AbstractFunction to merge with. + /// \return The merged AbstractFunction. AbstractFunctionPtr Join(const AbstractFunctionPtr &other) final; + /// Override the Visit function to perform an action on the current instance. + /// \param[in] func: A function that accepts an AbstractFuncAtomPtr and performs an action on it. void Visit(std::function) const final; + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return the type ID as a hash value. + /// \return The hash value based on the type ID. std::size_t hash() const override { return tid(); } }; @@ -80,14 +91,26 @@ class MS_CORE_API AbstractFuncUnion final : public AbstractFunction { /// \return Return true if other is in AbstractFuncUnion, otherwise return False. bool IsSuperSet(const AbstractFunctionPtr &other); + /// Override the Join function to merge two instances of AbstractFunction. + /// \param[in] other: Another instance of AbstractFunction to merge with. + /// \return The merged AbstractFunction. AbstractFunctionPtr Join(const AbstractFunctionPtr &other) final; + /// Override the Visit function to perform an action on the current instance. + /// \param[in] func: A function that accepts an AbstractFuncAtomPtr and performs an action on it. void Visit(std::function) const final; + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return the type ID as a hash value. + /// \return The hash value based on the type ID. std::size_t hash() const override; + /// Override the Copy function to create a copy of the current instance. + /// This function should not be used for AbstractFuncUnion, so it throws an exception. AbstractFunctionPtr Copy() const override { MS_LOG(EXCEPTION) << "Cannot Copy from AbstractFuncUnion"; } private: @@ -113,20 +136,38 @@ class MS_CORE_API PrimitiveAbstractClosure final : public AbstractFuncAtom { /// \return The Primitive that this PrimitiveAbstractClosure corresponding to. PrimitivePtr prim() { return prim_; } + /// Override the tracking_id function to get the tracking ID of this AbstractFunction. + /// \return The tracking ID of this AbstractFunction as an AnfNodePtr. AnfNodePtr tracking_id() const override { return tracking_id_.lock(); } + /// Override the set_tracking_id function to set the tracking ID of this AbstractFunction. + /// \param[in] node: The AnfNodePtr to set as the tracking ID. void set_tracking_id(AnfNodePtr node) override { tracking_id_ = AnfNodeWeakPtr(node); } + /// Override the Copy function to create a copy of the current instance. + /// \return A copy of the current AbstractFunction as an AbstractFunctionPtr. AbstractFunctionPtr Copy() const override { return std::make_shared(prim_, tracking_id()); } + /// Override the equality operator to compare the current instance with another AbstractFunction. + /// \param[in] other: Another AbstractFunction to compare with. + /// \return True if the two instances are equal, false otherwise. bool operator==(const AbstractFunction &other) const override; + /// Override the hash function to return a hash value based on the type ID. + /// \return The hash value based on the type ID. std::size_t hash() const override; + /// Override the ToString function to provide a string representation of this AbstractFunction. + /// \return A string describing this AbstractFunction. std::string ToString() const override { return "Prim: " + prim_->name(); } + /// Override the ToString function to provide a string representation of this AbstractFunction with verbosity. + /// \param[in] verbose: A flag indicating whether to include verbose information. + /// \return A string describing this AbstractFunction with optional verbosity. std::string ToString(bool verbose) const override; + /// Override the RealBuildValue function to return the associated primitive as a ValuePtr. + /// \return The primitive associated with this AbstractFunction as a ValuePtr. ValuePtr RealBuildValue() const override { return prim_; } private: diff --git a/mindspore/core/abstract/analysis_context.cc b/mindspore/core/abstract/analysis_context.cc index 6d56d843d21..84f0fa4e0d0 100644 --- a/mindspore/core/abstract/analysis_context.cc +++ b/mindspore/core/abstract/analysis_context.cc @@ -24,7 +24,13 @@ namespace mindspore { namespace abstract { +/// \brief A static list that stores all AnalysisContext instances. std::list AnalysisContext::all_context_; + +/// \brief Creates a new AnalysisContext for a given FuncGraph and argument specifications. +/// \param func_graph The FuncGraph for which the AnalysisContext is created. +/// \param args_spec_list The list of AbstractBasePtr representing argument specifications. +/// \return A shared pointer to the newly created AnalysisContext. AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, const AbstractBasePtrList &args_spec_list) { // Find func graph's parent and its parent context firstly. @@ -32,10 +38,14 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, FuncGraphPtr parent_graph = func_graph->parent(); AnalysisContextPtr parent_context = nullptr; auto iter = extant_context_cache_.find(parent_graph); + + // If the parent context exists in the cache, get a shared pointer to it. if (iter != extant_context_cache_.end()) { parent_context = iter->second.lock(); } - if (parent_context == nullptr) { // If parent context is not found, we'll raise exception. + + // If the parent context is not found, raise an exception with detailed information. + if (parent_context == nullptr) { std::ostringstream oss; oss << "BUG: Failed to find parent context in current context: " << this->ToString() << ", func_graph: " << func_graph->ToString() << ", parent_graph: "; @@ -52,6 +62,8 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, if (children_context_map_iter != parent_context->children_cache_.end()) { auto children_context_map = children_context_map_iter->second; auto children_context_iter = children_context_map.find(args_spec_list); + + // If a context with the same arguments exists in the cache, return a shared pointer to it. if (children_context_iter != children_context_map.end()) { return children_context_iter->second.lock(); } @@ -59,25 +71,36 @@ AnalysisContextPtr AnalysisContext::NewContext(const FuncGraphPtr &func_graph, // Create a new context for the func graph and its specific arguments. AnalysisContextPtr new_context = CreateContext(parent_context, func_graph, args_spec_list); + // To avoid cycle-reference, use weak_ptr here. auto weak_new_context = std::weak_ptr(new_context); new_context->extant_context_cache_[func_graph] = weak_new_context; parent_context->children_cache_[func_graph][args_spec_list] = weak_new_context; + return new_context; } +/// \brief Finds the AnalysisContext for a given FuncGraph or its parent FuncGraph. +/// \param func_graph The FuncGraph for which the AnalysisContext is searched. +/// \return A shared pointer to the found AnalysisContext. AnalysisContextPtr AnalysisContext::FindOwnOrParentContext(const FuncGraphPtr &func_graph) { auto p_iter = extant_context_cache_.find(func_graph); AnalysisContextPtr extant_context = nullptr; + + // If the context for the given FuncGraph is found in the cache, get a shared pointer to it. if (p_iter != extant_context_cache_.end()) { extant_context = p_iter->second.lock(); } else { + // If not found, try to find the context for its parent FuncGraph. auto iter_parent = extant_context_cache_.find(func_graph->parent()); + + // If found, get a shared pointer to the parent context. if (iter_parent != extant_context_cache_.end()) { extant_context = iter_parent->second.lock(); } } - // If this happen, it would be a bug in code. But we raise exception to keep the scene. + + // If the context is still not found, raise an exception with detailed information. if (extant_context == nullptr) { std::ostringstream oss; oss << "BUG: Failed to find context for: " << func_graph->ToString() << ", parent_graph: "; @@ -93,42 +116,55 @@ AnalysisContextPtr AnalysisContext::FindOwnOrParentContext(const FuncGraphPtr &f } else { oss << " [graph: " << iter.first->ToString(); } - // iter.second cannot be nullptr even iter.first is nullptr as it will + // iter.second cannot be nullptr even if iter.first is nullptr, as it will // always be a Context() object. oss << ", context: " << iter.second.lock()->ToString() << "]"; } oss << "}"; MS_LOG(EXCEPTION) << oss.str() << " NodeInfo: " << trace::GetDebugInfo(func_graph->debug_info()); } + return extant_context; } +/// \brief Creates a dummy AnalysisContext that represents no specific function or arguments. +/// \return A shared pointer to the created dummy AnalysisContext. AnalysisContextPtr AnalysisContext::DummyContext() { AnalysisContextPtr dummy_context = CreateContext(nullptr, nullptr, AbstractBasePtrList()); dummy_context->extant_context_cache_[nullptr] = std::weak_ptr(dummy_context); return dummy_context; } +/// \brief Checks if the AnalysisContext is a dummy context with no specific function or arguments. +/// \return True if it's a dummy context, false otherwise. bool AnalysisContext::IsDummyContext() { return parent_ == nullptr && func_graph_ == nullptr && args_spec_list_.empty(); } +/// \brief An instance of AnalysisContext that represents a dummy context. const AnalysisContextPtr kDummyAnalysisContext = AnalysisContext::CreateContext(nullptr, nullptr, AbstractBasePtrList()); +/// \brief Checks if two AnalysisContext instances are equal. +/// \param other The other AnalysisContext instance to compare with. +/// \return True if they are equal, false otherwise. bool AnalysisContext::operator==(const AnalysisContext &other) const { + // Check if func_graph_ is equal. if (func_graph_ != other.func_graph_) { return false; } + // Check if args_spec_list_ size is equal. if (args_spec_list_.size() != other.args_spec_list_.size()) { return false; } + // Check if parent_ is either both nullptr or both not nullptr. if (((parent_ == nullptr) && (other.parent_ != nullptr)) || ((parent_ != nullptr) && (other.parent_ == nullptr))) { return false; } - // Compare parent with content. + + // Compare parent_ with content. bool is_parent_equal = false; if (parent_ == other.parent_) { is_parent_equal = true; @@ -137,33 +173,43 @@ bool AnalysisContext::operator==(const AnalysisContext &other) const { } else { return false; } + + // Compare each element in args_spec_list_. for (std::size_t i = 0; i < args_spec_list_.size(); i++) { if (func_graph_->has_flag(GRAPH_FLAG_IS_WHILE_HEADER) && args_spec_list_[i]->isa() && other.args_spec_list_[i]->isa()) { + // If both are FuncGraphAbstractClosure, make a copy and compare without tracking IDs. auto temp_this = args_spec_list_[i]->cast()->Copy(); auto temp_other = other.args_spec_list_[i]->cast()->Copy(); temp_this->set_tracking_id(nullptr); temp_other->set_tracking_id(nullptr); + + // If the copies are not equal, return false. if (!(*temp_this == *temp_other)) { return false; } } else if (!(*args_spec_list_[i] == *other.args_spec_list_[i])) { + // If not both FuncGraphAbstractClosure, compare directly. return false; } } + return is_parent_equal; } - -// brief The key which controls the graph cloning in Specialize. -// Originally, specialize use context directly as the key for cloning graph. The graph will be cloned multiple times -// for different context, which means the graph is called from different node with different arguments and different -// free values. In order to decrease the number of cloned graphs, we add this `SpecializeKey` method to control what -// graph can be reused. -// The graph called with different shape should not be reused, because the combination of `shape` and `Fill` relies -// on correct shape to specialize a tensor constant. +/// \brief Generates a key for controlling graph cloning during specialization. +/// Originally, specialization used the context directly as the key for cloning graphs. This led to multiple clones of +/// the same graph for different contexts, where the graph was called from different nodes with varying arguments and +/// free values. To reduce the number of cloned graphs, this method, `SpecializeKey`, is introduced to determine which +/// graphs can be reused. +/// Graphs called with different shapes should not be reused because the specialization of a tensor constant depends on +/// the correct shape. +/// \return A new AnalysisContextPtr representing the specialized key. AnalysisContextPtr AnalysisContext::SpecializeKey() const { + // Create a list for broadened arguments. AbstractBasePtrList args_broad_shp; + + // Iterate through the args_spec_list_ and add the broadened version of each argument to args_broad_shp. (void)std::transform(args_spec_list_.begin(), args_spec_list_.end(), std::back_inserter(args_broad_shp), [](const AbstractBasePtr &arg) -> AbstractBasePtr { MS_EXCEPTION_IF_NULL(arg); @@ -173,23 +219,34 @@ AnalysisContextPtr AnalysisContext::SpecializeKey() const { } return arg; }); + + // Create a new AnalysisContext using the broadened arguments and the same function graph. AnalysisContextPtr context_new = CreateContext(nullptr, func_graph_, args_broad_shp); context_new->parent_ = parent_; + return context_new; } +/// \brief Computes a hash value for the AnalysisContext instance. +/// The hash value is used for hashing and comparison purposes. +/// \return The computed hash value. std::size_t AnalysisContext::hash() { std::size_t hash_value = 0; - // hash() recursion exit condition. + + // Recursion exit condition for hash(). if (parent_ != nullptr) { hash_value = hash_combine(hash_value, parent_->hash()); } if (func_graph_ != nullptr) { hash_value = hash_combine(hash_value, func_graph_->hash()); } + return hash_value; } +/// \brief Converts the AnalysisContext instance to a string representation. +/// This method is primarily used for debugging and logging purposes. +/// \return A string representing the AnalysisContext. std::string AnalysisContext::ToString() const { std::ostringstream buffer; buffer << "{"; @@ -209,6 +266,7 @@ std::string AnalysisContext::ToString() const { return buffer.str(); } +/// \brief Clears all contexts stored in the `all_context_` list. void AnalysisContext::ClearContext() { for (auto &item : all_context_) { item->parent_ = nullptr; @@ -220,6 +278,11 @@ void AnalysisContext::ClearContext() { all_context_.clear(); } +/// \brief Creates a new AnalysisContext instance. +/// \param parent The parent context. +/// \param fg The FuncGraph associated with the context. +/// \param args_spec_list The list of AbstractBasePtr representing argument specifications. +/// \return A shared pointer to the newly created AnalysisContext. AnalysisContextPtr AnalysisContext::CreateContext(const AnalysisContextPtr &parent, const FuncGraphPtr &fg, const AbstractBasePtrList &args_spec_list) { auto context = std::make_shared(parent, fg, args_spec_list); diff --git a/mindspore/core/abstract/analysis_context.h b/mindspore/core/abstract/analysis_context.h index 01a30bf707f..11908263060 100644 --- a/mindspore/core/abstract/analysis_context.h +++ b/mindspore/core/abstract/analysis_context.h @@ -47,38 +47,86 @@ class MS_CORE_API AnalysisContext { } ~AnalysisContext() = default; - // Extend this context with values for another graph. + /// Create a new AnalysisContext for a given function graph and its associated argument specifications. + /// \param[in] func_graph: The FuncGraphPtr representing the function graph for which to create the context. + /// \param[in] args_spec_list: The AbstractBasePtrList containing argument specifications. + /// \return A new AnalysisContextPtr representing the context for the given function graph and arguments. AnalysisContextPtr NewContext(const FuncGraphPtr &func_graph, const AbstractBasePtrList &args_spec_list); - // Return a context restricted to a graph and its parent. + /// Find the AnalysisContext for a given function graph, or its parent if not found. + /// \param[in] graph: The FuncGraphPtr for which to find the context. + /// \return The AnalysisContextPtr for the specified function graph or its parent. AnalysisContextPtr FindOwnOrParentContext(const FuncGraphPtr &graph); + + /// Override the equality operator to compare two AnalysisContext instances. + /// \param[in] other: Another AnalysisContext to compare with. + /// \return True if the two AnalysisContext instances are equal, false otherwise. bool operator==(const AnalysisContext &other) const; + + /// Calculate a hash value for the AnalysisContext instance. + /// \return The hash value for the AnalysisContext. std::size_t hash(); + + /// Create a dummy AnalysisContextPtr, typically used as a placeholder. + /// \return A dummy AnalysisContextPtr. static AnalysisContextPtr DummyContext(); + + /// Check if the current AnalysisContext is a dummy context. + /// \return True if the current context is a dummy context, false otherwise. bool IsDummyContext(); + + /// Get the function graph associated with this AnalysisContext. + /// \return The FuncGraphPtr associated with this context. FuncGraphPtr func_graph() const { return func_graph_; } + + /// Get the parent context of this AnalysisContext. + /// \return The parent AnalysisContextPtr of this context. AnalysisContextPtr parent() const { return parent_; } + + /// Convert the AnalysisContext to a string representation. + /// \return A string representation of the AnalysisContext. std::string ToString() const; + + /// Specialize the current context key. + /// \return A specialized AnalysisContextPtr based on the current context key. AnalysisContextPtr SpecializeKey() const; + + /// Get the list of argument specifications associated with this context. + /// \return The AbstractBasePtrList containing argument specifications. AbstractBasePtrList args_spec_list() { return args_spec_list_; } + + /// Clear the current context, typically used for resetting context information. static void ClearContext(); + + /// Create a new AnalysisContext with the given parent, function graph, and argument specifications. + /// \param[in] parent: The parent AnalysisContextPtr. + /// \param[in] fg: The FuncGraphPtr representing the function graph. + /// \param[in] args_spec_list: The AbstractBasePtrList containing argument specifications. + /// \return A new AnalysisContextPtr created with the specified parameters. static AnalysisContextPtr CreateContext(const AnalysisContextPtr &parent, const FuncGraphPtr &fg, const AbstractBasePtrList &args_spec_list); private: + // Pointer to the parent AnalysisContext. AnalysisContextPtr parent_; + + // Pointer to the associated function graph. FuncGraphPtr func_graph_; + + // List of argument specifications associated with this context. AbstractBasePtrList args_spec_list_; - // Record all created context for each func graph. - // `extant_context_cache_` is copied from its parent context. + + // A HashMap that records all created context instances for each function graph. + // The extant_context_cache_ is copied from its parent context. mindspore::HashMap extant_context_cache_; - // Record all created child contexts from this context. - // Like: key: [func_graph & arguments], value: [child_context] + + // A HashMap that records all created child contexts from this context. + // The key is a combination of [function graph & arguments], and the value is the child context. mindspore::HashMap children_cache_; - // There may may be shared_ptr loop like: - // FuncGraphAbstactClosur->AnalysisContext->children_cache_->ArgsSpec->FuncGraphAbstactClosur. - // For break the loop, using all_context_ to clear context_. + // There may be shared_ptr loops in the form of: + // FuncGraphAbstactClosure -> AnalysisContext -> children_cache_ -> ArgsSpec -> FuncGraphAbstactClosure. + // To break the loop, use all_context_ to clear context_. static std::list all_context_; }; diff --git a/mindspore/core/abstract/dshape.cc b/mindspore/core/abstract/dshape.cc index 79df160c18e..eb711a14ddc 100644 --- a/mindspore/core/abstract/dshape.cc +++ b/mindspore/core/abstract/dshape.cc @@ -25,6 +25,8 @@ std::string ShapeVectorToStr(const std::vector &shp) { std::ostringstream buffer; bool f_begin = true; buffer << "("; + + // Iterate through the elements of the shape vector. for (auto &x : shp) { if (!f_begin) { buffer << ", "; @@ -50,9 +52,15 @@ std::ostream &operator<<(std::ostream &os, const std::shared_ptr bs) return os; } -bool BaseShape::operator==(const BaseShape &other) const { return tid() == other.tid(); } +bool BaseShape::operator==(const BaseShape &other) const { + // Check if the type identifier of the shapes matches. + return tid() == other.tid(); +} -bool BaseShape::operator!=(const BaseShape &other) const { return !(*this == other); } +bool BaseShape::operator!=(const BaseShape &other) const { + // Check if the type identifier of the shapes does not match. + return !(*this == other); +} std::string Shape::ToString() const { std::ostringstream buffer; @@ -74,6 +82,8 @@ std::string Shape::ToString() const { std::string Shape::DumpText() const { std::ostringstream buffer; buffer << "["; + + // Iterate through the shape elements and add them to the string representation. for (size_t i = 0; i < shape_.size(); i++) { buffer << (i > 0 ? ", " : "") << shape_[i]; if (shape_[i] == SHP_ANY && min_shape_.size() == shape_.size() && max_shape_.size() == shape_.size()) { @@ -99,7 +109,9 @@ bool Shape::operator==(const BaseShape &other) const { } const int64_t Shape::SHP_ANY; + void Shape::Broaden() { + // Set all elements of the shape to SHP_ANY. for (size_t i = 0; i < shape_.size(); i++) { shape_[i] = SHP_ANY; } @@ -108,6 +120,8 @@ void Shape::Broaden() { std::string SequenceShape::ToString() const { std::ostringstream buffer; bool f_begin = true; + + // Iterate through the elements of p_shapes_ and add them to the string representation. for (const auto &p_shp : p_shapes_) { if (!f_begin) { buffer << ", "; @@ -122,6 +136,8 @@ std::string SequenceShape::ToString() const { BaseShapePtrList SequenceShape::ElementsClone() const { BaseShapePtrList ele_list; + + // Clone each element in p_shapes_ and add them to ele_list. for (auto p_shp : p_shapes_) { MS_EXCEPTION_IF_NULL(p_shp); ele_list.push_back(p_shp->Clone()); @@ -129,6 +145,7 @@ BaseShapePtrList SequenceShape::ElementsClone() const { return ele_list; } +// Explicit template instantiations for SequenceEqual. template bool SequenceShape::SequenceEqual(const BaseShape &) const; template bool SequenceShape::SequenceEqual(const BaseShape &) const; } // namespace abstract diff --git a/mindspore/core/abstract/param_validator.cc b/mindspore/core/abstract/param_validator.cc index 6c4f31998a4..36d075d52b2 100644 --- a/mindspore/core/abstract/param_validator.cc +++ b/mindspore/core/abstract/param_validator.cc @@ -26,6 +26,7 @@ namespace mindspore { namespace abstract { +// Define and initialize the ReportNameTraits for various Abstract types. #define ABSTRACT_REPORT_NAME_DEC(abstract) constexpr char ReportNameTraits::name[]; ABSTRACT_REPORT_NAME_DEC(Tensor) @@ -39,6 +40,7 @@ ABSTRACT_REPORT_NAME_DEC(Type) ABSTRACT_REPORT_NAME_DEC(KeywordArg) ABSTRACT_REPORT_NAME_DEC(Class) +// Check if the type of 'type' matches one of the 'accepts' types. TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &error_message_prefix) { auto ori_type = type; if (type->isa()) { @@ -46,15 +48,18 @@ TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &e type = tensor->element(); MS_EXCEPTION_IF_NULL(type); } + + // Check if 'type' is compatible with any of the 'accepts' types. bool ok = std::any_of(accepts.begin(), accepts.end(), [type](const TypePtr &accept) -> bool { return IsIdentidityOrSubclass(type, accept); }); if (ok) { return type; } else { - MS_EXCEPTION(TypeError) << error_message_prefix << " should be " << accepts << ",but got " << ori_type->ToString(); + MS_EXCEPTION(TypeError) << error_message_prefix << " should be " << accepts << ", but got " << ori_type->ToString(); } } +// Check if the dtype of 'tensor' matches one of the 'accepts' types. TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &accepts, const std::string &error_message_prefix) { MS_EXCEPTION_IF_NULL(tensor); @@ -66,6 +71,7 @@ TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &acc return CheckType(type, accepts, error_message_prefix); } +// Check if the dtypes of all tensors in 'tensor_list' match one of the 'accepts' types. TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const TypePtrList &accepts, const std::string &error_message_prefix) { if (tensor_list.empty()) { @@ -81,7 +87,8 @@ TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const Ty std::ostringstream loginfoBuffer; loginfoBuffer << "[" << sample_tensor->BuildType()->ToString(); bool error_flag = false; - // Check if other elements have the same type with the first element. + + // Check if the dtypes of all tensors in 'tensor_list' match the dtype of the first tensor. for (size_t index = 1; index < tensor_list.size(); ++index) { MS_EXCEPTION_IF_NULL(tensor_list[index]); auto elem = tensor_list[index]->element(); @@ -94,12 +101,13 @@ TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const Ty } } if (error_flag) { - MS_EXCEPTION(ValueError) << error_message_prefix << " must be same, but got " << loginfoBuffer.str() << "]"; + MS_EXCEPTION(ValueError) << error_message_prefix << " must be the same, but got " << loginfoBuffer.str() << "]"; } MS_LOG(DEBUG) << error_message_prefix << loginfoBuffer.str(); return CheckTensorDType(sample_tensor, accepts, error_message_prefix); } +// Check if the scalar's type matches one of the 'accepts' types. TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &accepts, const std::string &error_message_prefix) { if (scalar == nullptr) { @@ -113,6 +121,7 @@ TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &acce return CheckType(type, accepts, error_message_prefix); } +// Check if the shapes of two tensors are the same. void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor) { MS_EXCEPTION_IF_NULL(tensor_base); ShapePtr shape_base = tensor_base->shape(); @@ -128,7 +137,7 @@ void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, auto shape_base_vector = shape_base->shape(); if (shape_vector.size() != shape_base_vector.size()) { MS_LOG(EXCEPTION) << op << " evaluator first arg shape " << shape->ToString() - << " are not consistent with second arg shape " << shape_base->ToString(); + << " is not consistent with second arg shape " << shape_base->ToString(); } for (size_t i = 0; i < shape_vector.size(); i++) { @@ -137,12 +146,12 @@ void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, } if (shape_vector[i] != shape_base_vector[i]) { MS_LOG(EXCEPTION) << op << " evaluator first arg shape " << shape->ToString() - << " are not consistent with second arg shape " << shape_base->ToString(); + << " is not consistent with second arg shape " << shape_base->ToString(); } } - return; } +// Check if the dtype of two tensors is the same. TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor) { MS_EXCEPTION_IF_NULL(tensor_base); auto base_elem = tensor_base->element(); @@ -156,11 +165,12 @@ TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_ba MS_EXCEPTION_IF_NULL(type); if (*type != *type_base) { MS_LOG(EXCEPTION) << op << " evaluator first arg dtype " << type_base->ToString() - << " are not consistent with second arg dtype " << type->ToString(); + << " is not consistent with second arg dtype " << type->ToString(); } return type_base; } +// Check if 'axis' is within the valid range. int64_t CheckAxis(const std::string &op, const std::string &args_name, const ValuePtr &axis, int64_t minimum, int64_t max, const std::string &rank_name) { if (axis == nullptr) { @@ -180,6 +190,8 @@ int64_t CheckAxis(const std::string &op, const std::string &args_name, const Val } return axis_value; } + +// Check if the number of input arguments matches 'size_expect'. void CheckArgsSize(const std::string &op, const mindspore::abstract::AbstractBasePtrList &args_spec_list, size_t size_expect) { if (args_spec_list.size() != size_expect) { @@ -192,23 +204,26 @@ void CheckArgsSize(const std::string &op, const mindspore::abstract::AbstractBas } } +// Check if all elements in 'shape' are positive integers. void CheckShapeAllPositive(const std::string &op, const ShapeVector &shape) { for (size_t i = 0; i < shape.size(); ++i) { if (shape[i] < 0) { - MS_LOG(EXCEPTION) << op << " shape element [" << i << "] must be positive integer, but got " << shape[i]; + MS_LOG(EXCEPTION) << op << " shape element [" << i << "] must be a positive integer, but got " << shape[i]; } } } +// Check if all elements in 'shape' are either positive integers or SHP_ANY. void CheckShapeAnyAndPositive(const std::string &op, const ShapeVector &shape) { for (size_t i = 0; i < shape.size(); ++i) { if ((shape[i] < 0) && (shape[i] != Shape::SHP_ANY)) { - MS_EXCEPTION(ValueError) << op << " shape element [" << i << "] must be positive integer or SHP_ANY, but got " + MS_EXCEPTION(ValueError) << op << " shape element [" << i << "] must be a positive integer or SHP_ANY, but got " << shape[i]; } } } +// Check if the number of input arguments is at least 'size_expect'. void CheckRequiredArgsSize(const std::string &op, const mindspore::abstract::AbstractBasePtrList &args_spec_list, size_t size_expect) { if (args_spec_list.size() < size_expect) { diff --git a/mindspore/core/abstract/param_validator.h b/mindspore/core/abstract/param_validator.h index c088cdc08b8..62a47114c16 100644 --- a/mindspore/core/abstract/param_validator.h +++ b/mindspore/core/abstract/param_validator.h @@ -30,37 +30,99 @@ namespace mindspore { namespace abstract { -// check if variable's type is an instance of any of accepts or of a subclass of it. +/// \brief Checks if the given type is an instance of any of the accepted types or a subclass of them. +/// \param[in] type: The TypePtr to check. +/// \param[in] accepts: A list of accepted types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The input type if it is valid; otherwise, raises an error. TypePtr CheckType(TypePtr type, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks the data type of a tensor against a list of accepted types. +/// \param[in] tensor: The AbstractTensorPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input tensor if it is valid; otherwise, raises an error. TypePtr CheckTensorDType(const AbstractTensorPtr &tensor, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks that the data types of a list of tensors are the same and within the accepted types. +/// \param[in] tensor_list: A list of AbstractTensorPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input tensors if they are valid; otherwise, raises an error. TypePtr CheckTensorsDTypeSame(const AbstractTensorPtrList &tensor_list, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks the data type of a scalar against a list of accepted types. +/// \param[in] scalar: The AbstractScalarPtr to check. +/// \param[in] accepts: A list of accepted data types. +/// \param[in] error_message_prefix: A prefix to use in error messages if the check fails. +/// \return The data type of the input scalar if it is valid; otherwise, raises an error. TypePtr CheckScalarType(const AbstractScalarPtr &scalar, const TypePtrList &accepts, const std::string &error_message_prefix); +/// \brief Checks that the shapes of two tensors are the same. +/// \param[in] op: The name of the operation. +/// \param[in] tensor_base: The first AbstractTensorPtr to compare. +/// \param[in] tensor: The second AbstractTensorPtr to compare. void CheckShapeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor); +/// \brief Checks that the data types of two tensors are the same. +/// \param[in] op: The name of the operation. +/// \param[in] tensor_base: The first AbstractTensorPtr to compare. +/// \param[in] tensor: The second AbstractTensorPtr to compare. +/// \return The data type of the input tensors if they are valid; otherwise, raises an error. TypePtr CheckDtypeSame(const std::string &op, const AbstractTensorPtr &tensor_base, const AbstractTensorPtr &tensor); +/// \brief Checks the axis value within a specified range. +/// \param[in] op: The name of the operation. +/// \param[in] arg_name: The name of the argument. +/// \param[in] axis: The ValuePtr representing the axis to check. +/// \param[in] min: The minimum valid axis value. +/// \param[in] max: The maximum valid axis value. +/// \param[in] rank_name: The name of the rank argument for error messages. +/// \return The valid axis value. MS_CORE_API int64_t CheckAxis(const std::string &op, const std::string &arg_name, const ValuePtr &axis, int64_t min, int64_t max, const std::string &rank_name); -MS_CORE_API void CheckArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); +/// \brief Checks the size of a list of arguments. +/// \param[in] op: The name of the operation. +/// \param[in] args_spec_list: The list of AbstractBasePtr to check. +/// \param[in] size_expect: The expected size of the list. +void CheckArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); +/// \brief Checks that all values in the given shape are positive. +/// \param[in] op: The name of the operation. +/// \param[in] shape: The shape to check. void CheckShapeAllPositive(const std::string &op, const ShapeVector &shape); +/// \brief Checks that at least one value in the given shape is positive. +/// \param[in] op: The name of the operation. +/// \param[in] shape: The shape to check. void CheckShapeAnyAndPositive(const std::string &op, const ShapeVector &shape); +/// \brief Checks if the attribute is an integer or a tuple of integers. +/// \param[in] op: The name of the operation. +/// \param[in] attr: The ValuePtr representing the attribute to check. +/// \param[in] start_idx: The starting index of the attribute elements in case it's a tuple. +/// \param[in] num_element: The number of elements to check. +/// \return A vector of integers extracted from the attribute. std::vector CheckAttrIntOrTuple(const std::string &op, const ValuePtr &attr, const size_t start_idx, const size_t num_element); +/// \brief Checks if the attribute is a string within a set of valid values. +/// \param[in] op: The name of the operation. +/// \param[in] attr: The ValuePtr representing the attribute to check. +/// \param[in] attr_name: The name of the attribute for error messages. +/// \param[in] val_set: A set of valid string values. +/// \return The valid string attribute value. std::string CheckAttrStringSet(const std::string &op, const ValuePtr &attr, const std::string &attr_name, const std::set &val_set); +/// \brief Checks the size of a list of required arguments. +/// \param[in] op: The name of the operation. +/// \param[in] args_spec_list: The list of AbstractBasePtr to check. +/// \param[in] size_expect: The expected size of the list. void CheckRequiredArgsSize(const std::string &op, const AbstractBasePtrList &args_spec_list, size_t size_expect); template diff --git a/mindspore/core/abstract/prim_maths.cc b/mindspore/core/abstract/prim_maths.cc index 640cb6c7ed4..fb6dbcaf5e6 100644 --- a/mindspore/core/abstract/prim_maths.cc +++ b/mindspore/core/abstract/prim_maths.cc @@ -28,25 +28,33 @@ AbstractBasePtr InferImplMinOrMaxGrad(const AnalysisEnginePtr &, const Primitive constexpr auto kMinMaxGradInputNum = 3; const size_t dout_index = 2; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kMinMaxGradInputNum); + + // Get the input tensors and ensure their types and data types are as expected. auto input_x = CheckArg(op_name, args_spec_list, 0); auto input_y = CheckArg(op_name, args_spec_list, 1); auto dout = CheckArg(op_name, args_spec_list, dout_index); (void)CheckTensorsDTypeSame({input_x, input_y, dout}, {kInt, kUInt, kFloat}, - op_name + "evaluator three inputs should be %s"); + op_name + " evaluator three inputs should be %s"); + // Broaden the input tensors and return them as a tuple. AbstractBasePtr dx = input_x->Broaden(); AbstractBasePtr dy = input_y->Broaden(); - return std::make_shared(AbstractBasePtrList({dx, dy})); } AbstractBasePtr InferImplSqrt(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list) { - // Inputs: three tensors. + // Inputs: one tensor. constexpr auto kSqrtInputNum = 1; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kSqrtInputNum); + + // Get the input tensor and clone it with a Broaden operation. auto inp = CheckArg(op_name, args_spec_list, 0); return inp->Clone()->Broaden(); } @@ -56,12 +64,17 @@ AbstractBasePtr InferImplSqrtGrad(const AnalysisEnginePtr &, const PrimitivePtr // Inputs: two tensors. constexpr auto kSqrtGradInputNum = 2; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kSqrtGradInputNum); + + // Get the input tensors and ensure their data types and shapes match. auto out = CheckArg(op_name, args_spec_list, 0); auto dout = CheckArg(op_name, args_spec_list, 1); (void)CheckDtypeSame(op_name, out, dout); CheckShapeSame(op_name, out, dout); + // Broaden the output tensor and return it. return out->Broaden(); } @@ -80,9 +93,8 @@ int64_t InferImplReduceFuncCheckAxis(const int64_t &axis, const size_t dim) { void InferImplReduceFuncCalShape(ShapeVector *shape, const ShapeVector &x_shape, const ValuePtr &axis, bool keep_dims_value) { MS_EXCEPTION_IF_NULL(axis); - if (axis->isa() || axis->isa()) { - auto axis_ptr_list = - axis->isa() ? axis->cast()->value() : axis->cast()->value(); + if (axis->isa(ValueTuple) || axis->isa(ValueList)) { + auto axis_ptr_list = axis->isa(ValueTuple) ? axis->cast()->value() : axis->cast()->value(); if (!axis_ptr_list.size()) { if (keep_dims_value) (void)shape->insert(shape->end(), x_shape.size(), 1); } else { @@ -106,7 +118,7 @@ void InferImplReduceFuncCalShape(ShapeVector *shape, const ShapeVector &x_shape, } } } - } else if (axis->isa() || axis->isa()) { + } else if (axis->isa(Int32Imm) || axis->isa(Int64Imm)) { (void)shape->insert(shape->end(), x_shape.begin(), x_shape.end()); auto axis_value = GetValue(axis); axis_value = InferImplReduceFuncCheckAxis(axis_value, x_shape.size()); @@ -127,11 +139,16 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt const AbstractBasePtrList &args_spec_list) { const auto kReduceInputNum = 1; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kReduceInputNum); + + // Get the input tensor and its shape. auto input_x = CheckArg(op_name, args_spec_list, 0); MS_EXCEPTION_IF_NULL(input_x); MS_EXCEPTION_IF_NULL(input_x->element()); + // Get the "keep_dims" attribute and validate its type. ValuePtr keep_dims = primitive->GetAttr("keep_dims"); MS_EXCEPTION_IF_NULL(keep_dims); if (!keep_dims->isa()) { @@ -139,14 +156,18 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt } bool keep_dims_value = GetValue(keep_dims); + // Get the "axis" attribute. ValuePtr axis = primitive->GetAttr("axis"); MS_EXCEPTION_IF_NULL(axis); + // Calculate the output shape based on the input shape and axis. ShapeVector shape = {}; ShapeVector x_shape = input_x->shape()->shape(); InferImplReduceFuncCalShape(&shape, x_shape, axis, keep_dims_value); + // Check if the input tensor has dynamic shapes. bool x_is_dyn = (!input_x->shape()->min_shape().empty() && !input_x->shape()->max_shape().empty()); + if (x_is_dyn) { ShapeVector shape_min = {}; ShapeVector shape_max = {}; @@ -156,6 +177,7 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt InferImplReduceFuncCalShape(&shape_max, x_shape_max, axis, keep_dims_value); return std::make_shared(input_x->element(), std::make_shared(shape, shape_min, shape_max)); } + return std::make_shared(input_x->element(), std::make_shared(shape)); } @@ -163,47 +185,40 @@ AbstractBasePtr InferImplBinaryBase(const AnalysisEnginePtr &, const PrimitivePt const AbstractBasePtrList &args_spec_list) { constexpr auto kBinaryBaseInputNum = 2; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kBinaryBaseInputNum); + + // Get the input tensors and their shapes. auto input_x = CheckArg(op_name, args_spec_list, 0); - MS_EXCEPTION_IF_NULL(input_x); MS_EXCEPTION_IF_NULL(input_x->shape()); auto input_y = CheckArg(op_name, args_spec_list, 1); - MS_EXCEPTION_IF_NULL(input_y); MS_EXCEPTION_IF_NULL(input_y->shape()); auto x_shape = input_x->shape()->shape(); auto y_shape = input_y->shape()->shape(); + + // Compute the output shape by broadcasting the input shapes. auto output_shape = BroadcastShape(x_shape, y_shape); - auto x_type = input_x->BuildType(); - MS_EXCEPTION_IF_NULL(x_type); - MS_EXCEPTION_IF_NULL(x_type->cast()); - auto y_type = input_y->BuildType(); - MS_EXCEPTION_IF_NULL(y_type); - MS_EXCEPTION_IF_NULL(y_type->cast()); + // Get the data types of input tensors. + auto x_type = input_x->BuildType()->cast()->element(); + auto y_type = input_y->BuildType()->cast()->element(); - auto x_element = x_type->cast()->element(); - MS_EXCEPTION_IF_NULL(x_element); - auto y_element = y_type->cast()->element(); - MS_EXCEPTION_IF_NULL(y_element); + // Get the priority of data types. + auto x_priority = type_priority_map.find(x_type->number_type()); + auto y_priority = type_priority_map.find(y_type->number_type()); - auto x_element_type = x_element->number_type(); - auto y_element_type = y_element->number_type(); - - auto x_priority = type_priority_map.find(x_element_type); - if (x_priority == type_priority_map.end()) { - MS_LOG(EXCEPTION) << "input_x type is " << x_element_type << ", it's not number type."; - } - auto y_priority = type_priority_map.find(y_element_type); - if (y_priority == type_priority_map.end()) { - MS_LOG(EXCEPTION) << "input_y type is " << y_element_type << ", it's not number type."; + if (x_priority == type_priority_map.end() || y_priority == type_priority_map.end()) { + MS_LOG(EXCEPTION) << "Input types are not number types."; } + // Choose the element type based on priority. if (x_priority->second >= y_priority->second) { - return std::make_shared(input_x->element(), std::make_shared(output_shape)); + return std::make_shared(x_type, std::make_shared(output_shape)); } else { - return std::make_shared(input_y->element(), std::make_shared(output_shape)); + return std::make_shared(y_type, std::make_shared(output_shape)); } } @@ -221,22 +236,30 @@ AbstractBasePtr InferImplLinSpace(const AnalysisEnginePtr &, const PrimitivePtr const AbstractBasePtrList &args_spec_list) { constexpr auto kLinSpaceInputNum = 3; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kLinSpaceInputNum); + + // Get the start and stop input tensors. auto start = CheckArg(op_name, args_spec_list, 0); - MS_EXCEPTION_IF_NULL(start); MS_EXCEPTION_IF_NULL(start->shape()); + auto stop = CheckArg(op_name, args_spec_list, 1); - MS_EXCEPTION_IF_NULL(stop); MS_EXCEPTION_IF_NULL(stop->shape()); + + // Check data types of start and stop tensors. (void)CheckTensorDType(start, {kFloat32}, "Input 0 (start) for LinSpace should be %s"); (void)CheckTensorDType(stop, {kFloat32}, "Input 1 (stop) for LinSpace should be %s"); + ShapeVector shape; ShapeVector max_shape; ShapeVector min_shape; int64_t num_val = 0; - // 3rd input is a Tensor when LinSpace is a dynamic shape operator + + // The third input is a Tensor when LinSpace is a dynamic shape operator. const size_t tensor_index = 2; auto abs_num = args_spec_list[tensor_index]; + if (abs_num->isa()) { auto num = abs_num->cast(); MS_EXCEPTION_IF_NULL(num); @@ -251,187 +274,51 @@ AbstractBasePtr InferImplLinSpace(const AnalysisEnginePtr &, const PrimitivePtr } else { MS_LOG(EXCEPTION) << "Invalid abstract type:" << abs_num->type_name(); } + shape.emplace_back(num_val); + if (shape[0] < 0) { MS_LOG(EXCEPTION) << "num must be >= 0 in LinSpace"; } + max_shape.emplace_back(num_val); min_shape.emplace_back(num_val); - AbstractTensorPtr ret = - std::make_shared(start->element(), std::make_shared(shape, min_shape, max_shape)); + + // Create the output abstract tensor. + AbstractTensorPtr ret = std::make_shared( + start->element(), std::make_shared(shape, min_shape, max_shape)); return ret; } -AbstractBasePtr InferImplMatMul(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { - constexpr auto kMatMulInputNum = 2; - const std::string op_name = primitive->name(); - (void)CheckAndConvertUtils::CheckInteger("input number", SizeToLong(args_spec_list.size()), kGreaterEqual, - kMatMulInputNum, op_name); - auto x = CheckArg(op_name, args_spec_list, 0); - MS_EXCEPTION_IF_NULL(x); - MS_EXCEPTION_IF_NULL(x->shape()); - auto y = CheckArg(op_name, args_spec_list, 1); - MS_EXCEPTION_IF_NULL(y); - MS_EXCEPTION_IF_NULL(y->shape()); - auto x_shp = x->shape()->shape(); - auto y_shp = y->shape()->shape(); - const size_t SHAPE_SIZE = 2; - if (x_shp.size() != SHAPE_SIZE || y_shp.size() != SHAPE_SIZE) { - MS_LOG(EXCEPTION) << "MatMul inputs should have the same dimension size and equal to 2."; - } - ValuePtr transpose_a_ptr = primitive->GetAttr("transpose_a"); - ValuePtr transpose_b_ptr = primitive->GetAttr("transpose_b"); - bool transpose_a = GetValue(transpose_a_ptr); - bool transpose_b = GetValue(transpose_b_ptr); - ShapeVector x_min_shape = x->shape()->min_shape(); - ShapeVector x_max_shape = x->shape()->max_shape(); - ShapeVector y_min_shape = y->shape()->min_shape(); - ShapeVector y_max_shape = y->shape()->max_shape(); - CheckMinMaxShape(x_shp, &x_min_shape, &x_max_shape); - CheckMinMaxShape(y_shp, &y_min_shape, &y_max_shape); - // Additional check for dynamic shape - // Last infer will be real shape values - bool x_not_dyn = std::all_of(x_shp.begin(), x_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); - bool y_not_dyn = std::all_of(y_shp.begin(), y_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); - if (x_not_dyn && y_not_dyn) { - auto x_col = x_shp[(transpose_a ? 0 : 1)]; - auto y_row = y_shp[(transpose_b ? 1 : 0)]; - if (x_col != y_row) { - MS_LOG(EXCEPTION) << "MatMul shape error, got x_col: " << x_col << ", y_row: " << y_row - << ". In MatMul x_col and y_row should be equal."; - } - } - ShapeVector ret_shape; - ShapeVector ret_min_shape; - ShapeVector ret_max_shape; - auto make_shape = [&transpose_a, &transpose_b](ShapeVector &output, const ShapeVector xshp, - const ShapeVector yshp) -> void { - output.push_back(xshp[(transpose_a ? 1 : 0)]); - output.push_back(yshp[(transpose_b ? 0 : 1)]); - return; - }; - make_shape(ret_shape, x_shp, y_shp); - make_shape(ret_min_shape, x_min_shape, y_min_shape); - make_shape(ret_max_shape, x_max_shape, y_max_shape); - TypePtr x_type = x->element()->GetTypeTrack(); - if (x_type->type_id() == TypeId::kNumberTypeInt8) { - x_type = kInt32; - } - if (primitive->HasAttr("cast_type")) { - auto out_type = primitive->GetAttr("cast_type"); - MS_EXCEPTION_IF_NULL(out_type); - if (!out_type->isa()) { - MS_EXCEPTION(ValueError) << "MatMul cast_type must be a `Type`"; - } - x_type = out_type->cast(); - } - return std::make_shared(x_type, std::make_shared(ret_shape, ret_min_shape, ret_max_shape)); -} - -AbstractBasePtr InferImplBatchMatMul(const AnalysisEnginePtr &, const PrimitivePtr &primitive, - const AbstractBasePtrList &args_spec_list) { - constexpr auto kBatchMatMulInputNum = 2; - const std::string op_name = primitive->name(); - CheckArgsSize(op_name, args_spec_list, kBatchMatMulInputNum); - auto x = CheckArg(op_name, args_spec_list, 0); - MS_EXCEPTION_IF_NULL(x); - MS_EXCEPTION_IF_NULL(x->shape()); - auto y = CheckArg(op_name, args_spec_list, 1); - MS_EXCEPTION_IF_NULL(y); - MS_EXCEPTION_IF_NULL(y->shape()); - auto x_shp = x->shape()->shape(); - auto y_shp = y->shape()->shape(); - constexpr size_t minimum_shape = 3; - if (x_shp.size() != y_shp.size() || x_shp.size() < minimum_shape) { - MS_LOG(EXCEPTION) - << "BatchMatMul input x, y should have the same dimension size and should be greater or equal to 3."; - } - ValuePtr transpose_a_ptr = primitive->GetAttr("transpose_a"); - ValuePtr transpose_b_ptr = primitive->GetAttr("transpose_b"); - bool transpose_a = GetValue(transpose_a_ptr); - bool transpose_b = GetValue(transpose_b_ptr); - ShapeVector x_min_shape = x->shape()->min_shape(); - ShapeVector x_max_shape = x->shape()->max_shape(); - ShapeVector y_min_shape = y->shape()->min_shape(); - ShapeVector y_max_shape = y->shape()->max_shape(); - CheckMinMaxShape(x_shp, &x_min_shape, &x_max_shape); - CheckMinMaxShape(y_shp, &y_min_shape, &y_max_shape); - // Additional check for dynamic shape - // Last infer will be real shape values - bool x_not_dyn = std::all_of(x_shp.begin(), x_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); - bool y_not_dyn = std::all_of(y_shp.begin(), y_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); - if (x_not_dyn && y_not_dyn) { - size_t offset = x_shp.size() - 2; - auto x_col = x_shp[offset + (transpose_a ? 0 : 1)]; - auto y_row = y_shp[offset + (transpose_b ? 1 : 0)]; - if (x_col != y_row) { - MS_LOG(EXCEPTION) << "BatchMatMul shape error, got x_col: " << x_col << ", y_row: " << y_row - << ". In BatchMatMul x_col and y_row should be equal."; - } - } - ShapeVector ret_shape; - ShapeVector ret_min_shape; - ShapeVector ret_max_shape; - auto make_shape = [&transpose_a, &transpose_b](ShapeVector &output, const ShapeVector xshp, - const ShapeVector yshp) -> void { - for (size_t i = 0; i < xshp.size() - 2; i++) { - if (xshp[i] != yshp[i]) { - if (xshp[i] > 0 && yshp[i] > 0) { - MS_LOG(EXCEPTION) << "BatchMatMul input x, y are different at index " << i << "."; - } - output.push_back(Shape::SHP_ANY); - } else { - output.push_back(xshp[i]); - } - } - const size_t bias = 2; - size_t offset = xshp.size() - bias; - output.push_back(xshp[offset + (transpose_a ? 1 : 0)]); - output.push_back(yshp[offset + (transpose_b ? 0 : 1)]); - return; - }; - make_shape(ret_shape, x_shp, y_shp); - make_shape(ret_min_shape, x_min_shape, y_min_shape); - make_shape(ret_max_shape, x_max_shape, y_max_shape); - TypePtr x_type = x->element()->GetTypeTrack(); - if (x_type->type_id() == TypeId::kNumberTypeInt8) { - x_type = kInt32; - } - if (primitive->HasAttr("cast_type")) { - auto out_type = primitive->GetAttr("cast_type"); - MS_EXCEPTION_IF_NULL(out_type); - if (!out_type->isa()) { - MS_EXCEPTION(ValueError) << "MatMul cast_type must be a `Type`"; - } - x_type = out_type->cast(); - } - return std::make_shared(x_type, std::make_shared(ret_shape, ret_min_shape, ret_max_shape)); -} - AbstractBasePtr InferImplLess(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list) { constexpr auto kLessInputNum = 2; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kLessInputNum); + + // Get the input tensors and their shapes. auto x = CheckArg(op_name, args_spec_list, 0); - MS_EXCEPTION_IF_NULL(x); MS_EXCEPTION_IF_NULL(x->shape()); ShapeVector x_shape = x->shape()->shape(); ShapeVector x_shape_min = x->shape()->min_shape().empty() ? x_shape : x->shape()->min_shape(); ShapeVector x_shape_max = x->shape()->max_shape().empty() ? x_shape : x->shape()->max_shape(); auto y = CheckArg(op_name, args_spec_list, 1); - MS_EXCEPTION_IF_NULL(y); MS_EXCEPTION_IF_NULL(y->shape()); ShapeVector y_shape = y->shape()->shape(); ShapeVector y_shape_min = y->shape()->min_shape().empty() ? y_shape : y->shape()->min_shape(); ShapeVector y_shape_max = y->shape()->max_shape().empty() ? y_shape : y->shape()->max_shape(); + // Compute the output shape by broadcasting the input shapes. auto out_shape = BroadcastShape(x_shape, y_shape); auto out_shape_min = BroadcastShape(x_shape_min, y_shape_min); auto out_shape_max = BroadcastShape(x_shape_max, y_shape_max); + auto output_type = std::make_shared(); + + // Create the output abstract tensor. return std::make_shared(output_type, std::make_shared(out_shape, out_shape_min, out_shape_max)); } @@ -441,23 +328,39 @@ AbstractBasePtr InferImplReal(const AnalysisEnginePtr &, const PrimitivePtr &pri // Inputs: one tensors. constexpr auto kRealInputNum = 1; const std::string op_name = primitive->name(); + + // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kRealInputNum); + + // Get the input abstract base. AbstractBasePtr input_abs = args_spec_list[0]; + + // Check if the input is a tensor. auto input = dyn_cast(input_abs); + if (input == nullptr) { + // If the input is not a tensor, return a clone of the input abstract base. return input_abs->Clone(); } + + // Get the type of the input tensor. TypePtr input_type = input->element()->GetTypeTrack(); + TypePtr output_type = nullptr; + + // Determine the output type based on the input tensor type. if (input_type->type_id() == TypeId::kNumberTypeComplex64) { output_type = kFloat32; } else if (input_type->type_id() == TypeId::kNumberTypeComplex128) { output_type = kFloat64; } else { + // If the input type is not complex, return a clone of the input abstract base. return input_abs->Clone(); } + // Create the output abstract tensor. return std::make_shared(output_type, input->shape()); } + } // namespace abstract } // namespace mindspore diff --git a/mindspore/core/abstract/primitive_infer_map.cc b/mindspore/core/abstract/primitive_infer_map.cc index ab2a4243129..f893ea96870 100644 --- a/mindspore/core/abstract/primitive_infer_map.cc +++ b/mindspore/core/abstract/primitive_infer_map.cc @@ -45,9 +45,16 @@ namespace mindspore { namespace abstract { +// Function that returns a set of integers representing dependencies based on a primitive's name and input number. +// Parameters: +// - prim_name: A string representing the name of the primitive. +// - input_num: The number of inputs to the primitive. +// Returns: +// - A set of integers representing the dependencies. std::set GetDependsFormMap(const std::string &prim_name, size_t input_num) { using ShapeSet = std::set; using PrimShapeDependMap = mindspore::HashMap; + // Static mapping of primitive names to sets of integers representing dependencies. static const auto &kOneHot = prim::kPrimOneHot->name(); static const auto &kDropoutGenMask = prim::kPrimDropoutGenMask->name(); static const auto &kTranspose = prim::kPrimTranspose->name(); @@ -71,6 +78,7 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n static const auto &kReshape = prim::kPrimReshape->name(); static const auto &kFillV2 = prim::kPrimFillV2->name(); // Common dynamic shape depends. + // Define a map of dependencies for specific primitives. static const PrimShapeDependMap dynamic_shape_depends{{kUnsortedSegmentSum, ShapeSet{2}}, {kUnsortedSegmentMin, ShapeSet{2}}, {kUnsortedSegmentMax, ShapeSet{2}}, @@ -97,10 +105,11 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n MS_EXCEPTION_IF_NULL(ms_context); auto device = ms_context->get_param(MS_CTX_DEVICE_TARGET); // Special dynamic shape depends for Ascend. + // Special case for dynamic shape depends on Ascend device for the 'Transpose' primitive. if (device == kAscendDevice && prim_name == kTranspose) { return {1}; } - + // Look up the primitive name in the map and filter dependencies based on input number. auto iter = dynamic_shape_depends.find(prim_name); if (iter != dynamic_shape_depends.end()) { ShapeSet res; @@ -111,7 +120,11 @@ std::set GetDependsFormMap(const std::string &prim_name, size_t input_n } return {}; } - +// Function that returns a set of integers representing dependencies based on a CNode. +// Parameters: +// - cnode: A CNodePtr representing the computation node. +// Returns: +// - A set of integers representing the dependencies. std::set GetDependsFormMap(const CNodePtr &cnode) { MS_EXCEPTION_IF_NULL(cnode); if (cnode->inputs().empty()) { @@ -122,9 +135,11 @@ std::set GetDependsFormMap(const CNodePtr &cnode) { auto prim_name = primitive->ToString(); return GetDependsFormMap(prim_name, cnode->inputs().size() - 1); } - +// Function that provides a mapping between primitives and their shape and value inference implementations. +// - A map where primitive names (keys) are mapped to their corresponding inference implementations (values). PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap() { using R = PrimitiveEvalImplMap::mapped_type; + // Static mapping between primitive names and their inference implementations. static PrimitiveEvalImplMap prim_eval_implement_map{ // Statements {prim::kPrimReturn, R{InferImplReturn, nullptr, true}}, @@ -259,9 +274,12 @@ PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap() { }; return prim_eval_implement_map; } - +// Function that provides a mapping between primitives and their backend shape and value inference implementations. +// Returns: +// - A map where primitive names (keys) are mapped to their corresponding backend inference implementations (values). PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap() { using R = PrimitiveEvalImplMap::mapped_type; + // Static mapping between primitive names and their backend inference implementations. static PrimitiveEvalImplMap prim_backend_eval_implement_map = { {prim::kPrimMul, R{ops::MulInfer, nullptr, true}}, {prim::kPrimMod, R{ops::ModInfer, nullptr, true}}, @@ -314,7 +332,11 @@ PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap() { }; return prim_backend_eval_implement_map; } - +// Function that retrieves the shape and value inference implementations for a given primitive. +// Parameters: +// - primitive: A PrimitivePtr representing the primitive for which to retrieve the implementations. +// Returns: +// - A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive) { MS_EXCEPTION_IF_NULL(primitive); auto iter = GetPrimitiveToEvalImplMap().find(primitive); @@ -323,7 +345,10 @@ StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive) { } return iter->second; } - +// Function to register shape and value inference implementations for a primitive. +// Parameters: +// - primitive: A PrimitivePtr representing the primitive for which to register the implementations. +// - impl_reg: A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. void RegisterStandardPrimitiveImpl(const PrimitivePtr &primitive, const StandardPrimitiveImplReg &impl_reg) { auto &prim_eval_map = GetPrimitiveToEvalImplMap(); prim_eval_map[primitive] = impl_reg; diff --git a/mindspore/core/abstract/primitive_infer_map.h b/mindspore/core/abstract/primitive_infer_map.h index 99948ba7c92..8b38e5db0f9 100644 --- a/mindspore/core/abstract/primitive_infer_map.h +++ b/mindspore/core/abstract/primitive_infer_map.h @@ -31,33 +31,52 @@ namespace mindspore { namespace abstract { + +// Define function pointer types for shape and value inference for primitives. using InferShapeImpl = AbstractBasePtr (*)(const abstract::AnalysisEnginePtr &, const PrimitivePtr &, const AbstractBasePtrList &); using InferValueImpl = ValuePtr (*)(const PrimitivePtr &, const AbstractBasePtrList &); +// Structure to register shape and value inference implementations for primitives. struct StandardPrimitiveImplReg { - InferShapeImpl infer_shape_impl_; // infer shape and type for ops - InferValueImpl infer_value_impl_; // infer value for ops - // in_white_list_ is true means this primitive can be executed by vm backend - // else will be optimized by frontend - bool in_white_list_; + InferShapeImpl infer_shape_impl_; // Function pointer for shape inference. + InferValueImpl infer_value_impl_; // Function pointer for value inference. + bool in_white_list_; // Indicates if the primitive is in the white list for execution by the VM backend. }; +// Define a mapping between primitives and their shape and value inference implementations. using PrimitiveEvalImplMap = mindspore::HashMap; +/// \brief Provides a mapping between primitives and their shape and value inference implementations. +/// \return A map where primitive names (keys) are mapped to their corresponding inference implementations (values). MS_CORE_API PrimitiveEvalImplMap &GetPrimitiveToEvalImplMap(); +/// \brief Provides a mapping between primitives and their backend shape and value inference implementations. +/// \return A map where primitive names (keys) are mapped to their corresponding backend inference implementations (values). MS_CORE_API PrimitiveEvalImplMap &GetPrimitiveToBackendEvalImplMap(); + +/// \brief Retrieves the shape and value inference implementations for a given primitive. +/// \param[in] primitive: A PrimitivePtr representing the primitive for which to retrieve the implementations. +/// \return A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list. MS_CORE_API StandardPrimitiveImplReg GetPrimitiveInferImpl(const PrimitivePtr &primitive); +/// \brief get dependencies from a map for a given primitive name and input number. +/// \return A map where primitive names (keys) are mapped to their corresponding inference implementations (values). MS_CORE_API std::set GetDependsFormMap(const std::string &prim_name, size_t input_num); +/// \brief Get dependencies based on a CNode. +/// \param[in] cnode: A CNodePtr representing the computation node. +/// \return A set of integers representing the dependencies. MS_CORE_API std::set GetDependsFormMap(const CNodePtr &cnode); +/// \brief Registers shape and value inference implementations for a primitive. +/// \param[in] primitive: A PrimitivePtr representing the primitive for which to register the implementations. +/// \param[in] impl_reg: A StandardPrimitiveImplReg struct containing the inference implementations and a flag indicating if it's in the white list MS_CORE_API void RegisterStandardPrimitiveImpl(const PrimitivePtr &primitive, const StandardPrimitiveImplReg &impl_reg); +// Helper class for registering shape and value inference implementations for primitives. class RegisterStandardPrimitiveEvalHelper { public: RegisterStandardPrimitiveEvalHelper(const PrimitivePtr &primitive, const InferShapeImpl &infer_impl, @@ -68,6 +87,7 @@ class RegisterStandardPrimitiveEvalHelper { ~RegisterStandardPrimitiveEvalHelper() = default; }; +// Macro to simplify the registration of shape and value inference implementations for primitives. #define REGISTER_PRIMITIVE_EVAL_IMPL(name, primitive, infer_impl, infer_value_impl, is_white_list) \ static auto helper_##name = \ abstract::RegisterStandardPrimitiveEvalHelper(primitive, infer_impl, infer_value_impl, is_white_list); \ @@ -78,4 +98,4 @@ class RegisterStandardPrimitiveEvalHelper { ops::OpPrimCRegisterHelper primc_gen_##name(#name, GetDefaultPrimC##name); } // namespace abstract } // namespace mindspore -#endif // MINDSPORE_CORE_ABSTRACT_PRIMITIVE_INFER_MAP_H_ +#endif // MINDSPORE_CORE_ABSTRACT_PRIMITIVE_INFER_MAP_H_ \ No newline at end of file diff --git a/mindspore/core/abstract/utils.cc b/mindspore/core/abstract/utils.cc index 37127ff3906..05df2b504ec 100644 --- a/mindspore/core/abstract/utils.cc +++ b/mindspore/core/abstract/utils.cc @@ -24,6 +24,7 @@ namespace mindspore { namespace abstract { +// A mapping of MindSpore data types to their sizes in bytes const std::map type_map = { {kNumberTypeBool, 1}, {kNumberTypeInt, 4}, {kNumberTypeInt8, 1}, {kNumberTypeInt16, 2}, {kNumberTypeInt32, 4}, {kNumberTypeInt64, 8}, {kNumberTypeUInt, 4}, {kNumberTypeUInt8, 1}, @@ -31,26 +32,21 @@ const std::map type_map = { {kNumberTypeFloat16, 2}, {kNumberTypeFloat32, 4}, {kNumberTypeFloat64, 8}, {kNumberTypeComplex64, 8}, {kNumberTypeComplex128, 16}}; -ValuePtr ValueJoin(const ValuePtr &value1, const ValuePtr &value2) { - MS_EXCEPTION_IF_NULL(value1); - MS_EXCEPTION_IF_NULL(value2); - if (*value1 == *value2) { - return value1; - } - return kAnyValue; -} - +// Join two Type objects TypePtr TypeJoin(const TypePtr &type1, const TypePtr &type2) { MS_EXCEPTION_IF_NULL(type1); MS_EXCEPTION_IF_NULL(type2); + // If the two types are equal, return one of them if (*type1 == *type2) { return type1; } + // Otherwise, return a generic "Any" type return kAnyType; } +// Calculate the dynamic shape based on two shapes and a vector of dimensions ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, const ShapeVector &dims) { - // calculate dynamic shape + // Initialize min_dims and max_dims with the provided dimensions ShapeVector min_dims(dims.size()); ShapeVector max_dims(dims.size()); MS_EXCEPTION_IF_NULL(shape1); @@ -83,7 +79,7 @@ ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, c max_dims[i] = std::max(shape1->shape()[i], shape2->max_shape()[i]); continue; } - // both shapes contains dynamic shape + // Both shapes contain dynamic shape if (shape1->min_shape().size() <= i || shape1->max_shape().size() <= i) { MS_EXCEPTION(ValueError) << "Shape " << shape1->ToString() << " has dynamic shape, but does not have min/max shape info."; @@ -95,18 +91,21 @@ ShapePtr CalculateDynamicShape(const ShapePtr &shape1, const ShapePtr &shape2, c min_dims[i] = std::min(shape1->min_shape()[i], shape2->min_shape()[i]); max_dims[i] = std::max(shape1->max_shape()[i], shape2->max_shape()[i]); } + // Create a new Shape object with the calculated dynamic shape return std::make_shared(dims, min_dims, max_dims); } +// Join two Shape objects ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2) { MS_EXCEPTION_IF_NULL(shape1); MS_EXCEPTION_IF_NULL(shape2); + // If the two shapes are equal, return one of them if (*shape1 == *shape2) { return shape1; } - // lengths of two shapes are not same, join failed + // If the lengths of the two shapes are not the same, join failed if (shape1->shape().size() != shape2->shape().size()) { - // special case: shape(1), shape() -> shape(1) + // Special case: shape(1), shape() -> shape(1) if (shape1->shape().size() == 1 && shape1->shape()[0] == 1 && shape2->shape().empty()) { return shape1; } @@ -130,35 +129,41 @@ ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2) { } } if (!has_dynamic_shape) { + // If there are no dynamic shapes, return a new Shape with the calculated dimensions return std::make_shared(dims); } + // If there are dynamic shapes, calculate the dynamic shape based on the two shapes and dimensions return CalculateDynamicShape(shape1, shape2, dims); } +// Join a list of AbstractBasePtr objects AbstractBasePtr AbstractJoin(const AbstractBasePtrList &args_spec_list) { if (args_spec_list.empty()) { - MS_LOG(EXCEPTION) << "AbstractJoin requires at least 1 params, while the input size is " << args_spec_list.size() + MS_LOG(EXCEPTION) << "AbstractJoin requires at least 1 parameter, but the input size is " << args_spec_list.size() << "."; } AbstractBasePtr arg_spec_tmp = args_spec_list[0]; MS_EXCEPTION_IF_NULL(arg_spec_tmp); for (const auto &arg_spec : args_spec_list) { MS_EXCEPTION_IF_NULL(arg_spec); + // Join the AbstractBasePtr objects to create a new one arg_spec_tmp = arg_spec_tmp->Join(arg_spec); MS_EXCEPTION_IF_NULL(arg_spec_tmp); } return arg_spec_tmp; } +// Join two lists of AbstractBasePtr objects AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const AbstractBasePtrList &spec2) { if (spec1.size() != spec2.size()) { - MS_LOG(EXCEPTION) << "Join failed as list don't have the same size. spec1: " << ::mindspore::ToString(spec1) - << ", spec2: " << ::mindspore::ToString(spec2); + MS_LOG(EXCEPTION) << "Join failed because the lists do not have the same size. spec1: " + << ::mindspore::ToString(spec1) << ", spec2: " << ::mindspore::ToString(spec2); } AbstractBasePtrList joined_list; bool changes = false; for (std::size_t i = 0; i < spec1.size(); i++) { MS_EXCEPTION_IF_NULL(spec1[i]); + // Join each pair of AbstractBasePtr objects in the lists auto joined_elem = spec1[i]->Join(spec2[i]); MS_EXCEPTION_IF_NULL(joined_elem); if (joined_elem != spec1[i]) { @@ -167,20 +172,28 @@ AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const Abstrac joined_list.push_back(joined_elem); } if (!changes) { + // If there are no changes, return spec1 return spec1; } + // Otherwise, return the joined_list return joined_list; } +// Transform an AbstractBasePtr into its sensitivity AbstractBasePtr SensitivityTransform(const AbstractBasePtr &spec) { + // Check if the spec is an AbstractFunction AbstractFunctionPtr f_spec = dyn_cast(spec); if (f_spec != nullptr) { + // If it is, return an AbstractScalar with "AnyValue" and an EnvType return std::make_shared(kAnyValue, std::make_shared()); } + // Otherwise, return a clone of the spec return spec->Clone(); } +// Broadcast two ShapeVectors to have the same dimensions ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { + // Calculate the difference in dimensions int dlen = SizeToInt(shpx.size()) - SizeToInt(shpy.size()); if (dlen < 0) { for (int i = 0; i < -dlen; ++i) { @@ -191,6 +204,7 @@ ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { (void)shpy.insert(shpy.begin(), 1); } } + // Check if the two ShapeVectors have the same size if (shpx.size() != shpy.size()) { MS_LOG(EXCEPTION) << "Failure: shpx.size() != shpy.size()."; } @@ -209,26 +223,34 @@ ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy) { } else if (a == b) { shp.push_back(a); } else { + // If dimensions are incompatible, return an empty ShapeVector return ShapeVector(); } } + // Return the broadcasted ShapeVector return shp; } +// Get the size in bytes for a given data type size_t TypeIdSize(const TypeId data_type) { const size_t unsupported_type_error = 0; auto iter = type_map.find(data_type); if (iter != type_map.end()) { return iter->second; } + // If the data type is not in the map, return 0 (unsupported type) return unsupported_type_error; } +// Check and update the minimum and maximum shapes based on a new shape void CheckMinMaxShape(const ShapeVector &shape, ShapeVector *min_shape, ShapeVector *max_shape) { + // If min_shape is empty, set it to the new shape *min_shape = (*min_shape).empty() ? shape : *min_shape; + // If max_shape is empty, set it to the new shape *max_shape = (*max_shape).empty() ? shape : *max_shape; } +// Create an AbstractTensor with the given shape and type AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type) { MS_EXCEPTION_IF_NULL(shape); MS_EXCEPTION_IF_NULL(type); @@ -254,18 +276,22 @@ AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type) { auto element = std::make_shared(kAnyValue, type); tensor = std::make_shared(element, ret_shape); } + // Return the created AbstractTensor return tensor; } +// Create a Monad abstract based on the given MonadType AbstractBasePtr MakeMonadAbstract(const MonadTypePtr &type) { if (type->isa()) { return kUMonad->ToAbstract(); } else if (type->isa()) { return kIOMonad->ToAbstract(); } + // Raise an exception for unsupported MonadType MS_EXCEPTION(UnknownError) << "Unsupported to convert type " << type->ToString() << " to monad abstract"; } +// Create an AbstractBasePtr based on a BaseShapePtr and a TypePtr AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type) { MS_EXCEPTION_IF_NULL(base_shape); MS_EXCEPTION_IF_NULL(type); @@ -273,11 +299,12 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto shape = base_shape->cast(); MS_EXCEPTION_IF_NULL(shape); auto shape_vec = shape->shape(); - // if the size of shape list is empty, return an scalar abstract + // If the size of shape list is empty and the type is not TensorType, return an AbstractScalar if (shape_vec.empty() && (!type->isa())) { abstract::AbstractScalarPtr abs_scalar = std::make_shared(kAnyValue, type); return abs_scalar; } + // Create an AbstractTensor based on the given shape and type return MakeAbstractTensor(shape, type); } else if (base_shape->isa() && type->isa()) { auto shape_tuple = base_shape->cast(); @@ -287,6 +314,7 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto tensor_it = MakeAbstract((*shape_tuple)[it], (*type_tuple)[it]); ptr_list.push_back(tensor_it); } + // Create an AbstractTuple based on the given list of AbstractBasePtr auto tuple = std::make_shared(ptr_list); return tuple; } else if (base_shape->isa() && type->isa()) { @@ -297,6 +325,7 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto tensor_it = MakeAbstract((*shape_list)[it], (*type_list)[it]); ptr_list.push_back(tensor_it); } + // Create an AbstractList based on the given list of AbstractBasePtr auto list = std::make_shared(ptr_list); return list; } else if (base_shape->isa() && type->isa()) { @@ -304,18 +333,20 @@ AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type auto abstract_none = std::make_shared(); return abstract_none; } else if (type->isa()) { - // Return monad abstract if it is monad type. + // Return a Monad abstract if it is a MonadType return MakeMonadAbstract(type->cast()); } else { - // When sparse enabled, the undetermined might be raised and eliminated in opt passes + // When sparse is enabled, the "Undetermined" type might be raised and eliminated in optimization passes auto context = MsContext::GetInstance(); MS_EXCEPTION_IF_NULL(context); bool enable_sparse = context->get_param(MS_CTX_ENABLE_SPARSE); if (enable_sparse) { return std::make_shared(); } - MS_LOG(EXCEPTION) << "evaluator return invalid shape " << base_shape->ToString() << "or type. " << type->ToString(); + MS_LOG(EXCEPTION) << "Evaluator returned an invalid shape " << base_shape->ToString() << " or type " + << type->ToString(); } } + } // namespace abstract -} // namespace mindspore +} // namespace mindspore \ No newline at end of file diff --git a/mindspore/core/abstract/utils.h b/mindspore/core/abstract/utils.h index 5a98da43911..39648fd61a3 100644 --- a/mindspore/core/abstract/utils.h +++ b/mindspore/core/abstract/utils.h @@ -32,32 +32,102 @@ namespace mindspore { namespace abstract { + +/// \brief Joins two values. + +/// \param[in] value1: The first ValuePtr to join. +/// \param[in] value2: The second ValuePtr to join. + +/// \return A ValuePtr representing the result of joining value1 and value2. ValuePtr ValueJoin(const ValuePtr &value1, const ValuePtr &value2); + +/// \brief Joins two types. + +/// \param[in] type1: The first TypePtr to join. +/// \param[in] type2: The second TypePtr to join. + +/// \return A TypePtr representing the result of joining type1 and type2. MS_CORE_API TypePtr TypeJoin(const TypePtr &type1, const TypePtr &type2); + +/// \brief Joins two shapes. + +/// \param[in] shape1: The first ShapePtr to join. +/// \param[in] shape2: The second ShapePtr to join. + +/// \return A ShapePtr representing the result of joining shape1 and shape2. ShapePtr ShapeJoin(const ShapePtr &shape1, const ShapePtr &shape2); +/// \brief Joins a list of AbstractBasePtr. + +/// \param[in] args_spec_list: A list of AbstractBasePtr to join. + +/// \return An AbstractBasePtr representing the result of joining the input AbstractBasePtrs. MS_CORE_API AbstractBasePtr AbstractJoin(const AbstractBasePtrList &args_spec_list); + +/// \brief Joins two lists of AbstractBasePtr. + +/// \param[in] spec1: The first list of AbstractBasePtr to join. +/// \param[in] spec2: The second list of AbstractBasePtr to join. + +/// \return A list of AbstractBasePtr representing the result of joining spec1 and spec2. MS_CORE_API AbstractBasePtrList AbstractJoin(const AbstractBasePtrList &spec1, const AbstractBasePtrList &spec2); -// Return an abstract value for the sensitivity of x. -// The sensitivity of a function is an Env -// The sensitivity of J(x) is x -// else self.Clone; +/// \brief Transforms the sensitivity of an AbstractBasePtr. + +/// \param[in] spec: The AbstractBasePtr to transform. + +/// \return An AbstractBasePtr representing the transformed AbstractBasePtr. MS_CORE_API AbstractBasePtr SensitivityTransform(const AbstractBasePtr &spec); +/// \brief Computes the broadcasted shape of two ShapeVectors. + +/// \param[in] shpx: The first ShapeVector. +/// \param[in] shpy: The second ShapeVector. + +/// \return A ShapeVector representing the broadcasted shape of shpx and shpy. ShapeVector BroadcastShape(ShapeVector shpx, ShapeVector shpy); + +/// \brief Returns the size of a data type based on its TypeId. + +/// \param[in] data_type: The TypeId of the data type. + +/// \return The size of the data type in bytes. MS_CORE_API size_t TypeIdSize(const TypeId data_type); -template + T ShapeSize(const std::vector &shape) { return std::accumulate(shape.begin(), shape.end(), static_cast(1), std::multiplies()); } -// Check dynamic shape routine +/// \brief Checks and updates the minimum and maximum shapes based on the given shape. + +/// \param[in] shape: The shape to check. +/// \param[in, out] min_shape: A pointer to the minimum shape vector, which will be updated if the input shape is smaller. +/// \param[in, out] max_shape: A pointer to the maximum shape vector, which will be updated if the input shape is larger. void CheckMinMaxShape(const ShapeVector &shape, ShapeVector *min_shape, ShapeVector *max_shape); +/// \brief Creates an AbstractBasePtr from a BaseShapePtr and a TypePtr. + +/// \param[in] base_shape: The BaseShapePtr to use for creating the AbstractBasePtr. +/// \param[in] type: The TypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified shape and type. AbstractBasePtr MakeAbstract(const BaseShapePtr &base_shape, const TypePtr &type); + +/// \brief Creates an AbstractBasePtr from a MonadTypePtr. + +/// \param[in] type: The MonadTypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified monadic type. MS_CORE_API AbstractBasePtr MakeMonadAbstract(const MonadTypePtr &type); + +/// \brief Creates an AbstractBasePtr from a ShapePtr and a TypePtr. + +/// \param[in] shape: The ShapePtr to use for creating the AbstractBasePtr. +/// \param[in] type: The TypePtr to use for creating the AbstractBasePtr. + +/// \return An AbstractBasePtr representing the specified shape and type. MS_CORE_API AbstractBasePtr MakeAbstractTensor(const ShapePtr &shape, const TypePtr &type); + } // namespace abstract } // namespace mindspore #endif // MINDSPORE_CORE_ABSTRACT_UTILS_H_ -- 2.34.1 From de11602f33dc5485b2c1e9b50120ce11bcfb677c Mon Sep 17 00:00:00 2001 From: iku50 Date: Tue, 3 Oct 2023 13:06:14 +0800 Subject: [PATCH 2/3] ok --- mindspore/core/abstract/prim_maths.cc | 273 +++++++++++++++++--------- 1 file changed, 185 insertions(+), 88 deletions(-) diff --git a/mindspore/core/abstract/prim_maths.cc b/mindspore/core/abstract/prim_maths.cc index fb6dbcaf5e6..640cb6c7ed4 100644 --- a/mindspore/core/abstract/prim_maths.cc +++ b/mindspore/core/abstract/prim_maths.cc @@ -28,33 +28,25 @@ AbstractBasePtr InferImplMinOrMaxGrad(const AnalysisEnginePtr &, const Primitive constexpr auto kMinMaxGradInputNum = 3; const size_t dout_index = 2; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kMinMaxGradInputNum); - - // Get the input tensors and ensure their types and data types are as expected. auto input_x = CheckArg(op_name, args_spec_list, 0); auto input_y = CheckArg(op_name, args_spec_list, 1); auto dout = CheckArg(op_name, args_spec_list, dout_index); (void)CheckTensorsDTypeSame({input_x, input_y, dout}, {kInt, kUInt, kFloat}, - op_name + " evaluator three inputs should be %s"); + op_name + "evaluator three inputs should be %s"); - // Broaden the input tensors and return them as a tuple. AbstractBasePtr dx = input_x->Broaden(); AbstractBasePtr dy = input_y->Broaden(); + return std::make_shared(AbstractBasePtrList({dx, dy})); } AbstractBasePtr InferImplSqrt(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list) { - // Inputs: one tensor. + // Inputs: three tensors. constexpr auto kSqrtInputNum = 1; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kSqrtInputNum); - - // Get the input tensor and clone it with a Broaden operation. auto inp = CheckArg(op_name, args_spec_list, 0); return inp->Clone()->Broaden(); } @@ -64,17 +56,12 @@ AbstractBasePtr InferImplSqrtGrad(const AnalysisEnginePtr &, const PrimitivePtr // Inputs: two tensors. constexpr auto kSqrtGradInputNum = 2; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kSqrtGradInputNum); - - // Get the input tensors and ensure their data types and shapes match. auto out = CheckArg(op_name, args_spec_list, 0); auto dout = CheckArg(op_name, args_spec_list, 1); (void)CheckDtypeSame(op_name, out, dout); CheckShapeSame(op_name, out, dout); - // Broaden the output tensor and return it. return out->Broaden(); } @@ -93,8 +80,9 @@ int64_t InferImplReduceFuncCheckAxis(const int64_t &axis, const size_t dim) { void InferImplReduceFuncCalShape(ShapeVector *shape, const ShapeVector &x_shape, const ValuePtr &axis, bool keep_dims_value) { MS_EXCEPTION_IF_NULL(axis); - if (axis->isa(ValueTuple) || axis->isa(ValueList)) { - auto axis_ptr_list = axis->isa(ValueTuple) ? axis->cast()->value() : axis->cast()->value(); + if (axis->isa() || axis->isa()) { + auto axis_ptr_list = + axis->isa() ? axis->cast()->value() : axis->cast()->value(); if (!axis_ptr_list.size()) { if (keep_dims_value) (void)shape->insert(shape->end(), x_shape.size(), 1); } else { @@ -118,7 +106,7 @@ void InferImplReduceFuncCalShape(ShapeVector *shape, const ShapeVector &x_shape, } } } - } else if (axis->isa(Int32Imm) || axis->isa(Int64Imm)) { + } else if (axis->isa() || axis->isa()) { (void)shape->insert(shape->end(), x_shape.begin(), x_shape.end()); auto axis_value = GetValue(axis); axis_value = InferImplReduceFuncCheckAxis(axis_value, x_shape.size()); @@ -139,16 +127,11 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt const AbstractBasePtrList &args_spec_list) { const auto kReduceInputNum = 1; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kReduceInputNum); - - // Get the input tensor and its shape. auto input_x = CheckArg(op_name, args_spec_list, 0); MS_EXCEPTION_IF_NULL(input_x); MS_EXCEPTION_IF_NULL(input_x->element()); - // Get the "keep_dims" attribute and validate its type. ValuePtr keep_dims = primitive->GetAttr("keep_dims"); MS_EXCEPTION_IF_NULL(keep_dims); if (!keep_dims->isa()) { @@ -156,18 +139,14 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt } bool keep_dims_value = GetValue(keep_dims); - // Get the "axis" attribute. ValuePtr axis = primitive->GetAttr("axis"); MS_EXCEPTION_IF_NULL(axis); - // Calculate the output shape based on the input shape and axis. ShapeVector shape = {}; ShapeVector x_shape = input_x->shape()->shape(); InferImplReduceFuncCalShape(&shape, x_shape, axis, keep_dims_value); - // Check if the input tensor has dynamic shapes. bool x_is_dyn = (!input_x->shape()->min_shape().empty() && !input_x->shape()->max_shape().empty()); - if (x_is_dyn) { ShapeVector shape_min = {}; ShapeVector shape_max = {}; @@ -177,7 +156,6 @@ AbstractBasePtr InferImplReduceFunc(const AnalysisEnginePtr &, const PrimitivePt InferImplReduceFuncCalShape(&shape_max, x_shape_max, axis, keep_dims_value); return std::make_shared(input_x->element(), std::make_shared(shape, shape_min, shape_max)); } - return std::make_shared(input_x->element(), std::make_shared(shape)); } @@ -185,40 +163,47 @@ AbstractBasePtr InferImplBinaryBase(const AnalysisEnginePtr &, const PrimitivePt const AbstractBasePtrList &args_spec_list) { constexpr auto kBinaryBaseInputNum = 2; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kBinaryBaseInputNum); - - // Get the input tensors and their shapes. auto input_x = CheckArg(op_name, args_spec_list, 0); + MS_EXCEPTION_IF_NULL(input_x); MS_EXCEPTION_IF_NULL(input_x->shape()); auto input_y = CheckArg(op_name, args_spec_list, 1); + MS_EXCEPTION_IF_NULL(input_y); MS_EXCEPTION_IF_NULL(input_y->shape()); auto x_shape = input_x->shape()->shape(); auto y_shape = input_y->shape()->shape(); - - // Compute the output shape by broadcasting the input shapes. auto output_shape = BroadcastShape(x_shape, y_shape); - // Get the data types of input tensors. - auto x_type = input_x->BuildType()->cast()->element(); - auto y_type = input_y->BuildType()->cast()->element(); + auto x_type = input_x->BuildType(); + MS_EXCEPTION_IF_NULL(x_type); + MS_EXCEPTION_IF_NULL(x_type->cast()); + auto y_type = input_y->BuildType(); + MS_EXCEPTION_IF_NULL(y_type); + MS_EXCEPTION_IF_NULL(y_type->cast()); - // Get the priority of data types. - auto x_priority = type_priority_map.find(x_type->number_type()); - auto y_priority = type_priority_map.find(y_type->number_type()); + auto x_element = x_type->cast()->element(); + MS_EXCEPTION_IF_NULL(x_element); + auto y_element = y_type->cast()->element(); + MS_EXCEPTION_IF_NULL(y_element); - if (x_priority == type_priority_map.end() || y_priority == type_priority_map.end()) { - MS_LOG(EXCEPTION) << "Input types are not number types."; + auto x_element_type = x_element->number_type(); + auto y_element_type = y_element->number_type(); + + auto x_priority = type_priority_map.find(x_element_type); + if (x_priority == type_priority_map.end()) { + MS_LOG(EXCEPTION) << "input_x type is " << x_element_type << ", it's not number type."; + } + auto y_priority = type_priority_map.find(y_element_type); + if (y_priority == type_priority_map.end()) { + MS_LOG(EXCEPTION) << "input_y type is " << y_element_type << ", it's not number type."; } - // Choose the element type based on priority. if (x_priority->second >= y_priority->second) { - return std::make_shared(x_type, std::make_shared(output_shape)); + return std::make_shared(input_x->element(), std::make_shared(output_shape)); } else { - return std::make_shared(y_type, std::make_shared(output_shape)); + return std::make_shared(input_y->element(), std::make_shared(output_shape)); } } @@ -236,30 +221,22 @@ AbstractBasePtr InferImplLinSpace(const AnalysisEnginePtr &, const PrimitivePtr const AbstractBasePtrList &args_spec_list) { constexpr auto kLinSpaceInputNum = 3; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kLinSpaceInputNum); - - // Get the start and stop input tensors. auto start = CheckArg(op_name, args_spec_list, 0); + MS_EXCEPTION_IF_NULL(start); MS_EXCEPTION_IF_NULL(start->shape()); - auto stop = CheckArg(op_name, args_spec_list, 1); + MS_EXCEPTION_IF_NULL(stop); MS_EXCEPTION_IF_NULL(stop->shape()); - - // Check data types of start and stop tensors. (void)CheckTensorDType(start, {kFloat32}, "Input 0 (start) for LinSpace should be %s"); (void)CheckTensorDType(stop, {kFloat32}, "Input 1 (stop) for LinSpace should be %s"); - ShapeVector shape; ShapeVector max_shape; ShapeVector min_shape; int64_t num_val = 0; - - // The third input is a Tensor when LinSpace is a dynamic shape operator. + // 3rd input is a Tensor when LinSpace is a dynamic shape operator const size_t tensor_index = 2; auto abs_num = args_spec_list[tensor_index]; - if (abs_num->isa()) { auto num = abs_num->cast(); MS_EXCEPTION_IF_NULL(num); @@ -274,51 +251,187 @@ AbstractBasePtr InferImplLinSpace(const AnalysisEnginePtr &, const PrimitivePtr } else { MS_LOG(EXCEPTION) << "Invalid abstract type:" << abs_num->type_name(); } - shape.emplace_back(num_val); - if (shape[0] < 0) { MS_LOG(EXCEPTION) << "num must be >= 0 in LinSpace"; } - max_shape.emplace_back(num_val); min_shape.emplace_back(num_val); - - // Create the output abstract tensor. - AbstractTensorPtr ret = std::make_shared( - start->element(), std::make_shared(shape, min_shape, max_shape)); + AbstractTensorPtr ret = + std::make_shared(start->element(), std::make_shared(shape, min_shape, max_shape)); return ret; } +AbstractBasePtr InferImplMatMul(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { + constexpr auto kMatMulInputNum = 2; + const std::string op_name = primitive->name(); + (void)CheckAndConvertUtils::CheckInteger("input number", SizeToLong(args_spec_list.size()), kGreaterEqual, + kMatMulInputNum, op_name); + auto x = CheckArg(op_name, args_spec_list, 0); + MS_EXCEPTION_IF_NULL(x); + MS_EXCEPTION_IF_NULL(x->shape()); + auto y = CheckArg(op_name, args_spec_list, 1); + MS_EXCEPTION_IF_NULL(y); + MS_EXCEPTION_IF_NULL(y->shape()); + auto x_shp = x->shape()->shape(); + auto y_shp = y->shape()->shape(); + const size_t SHAPE_SIZE = 2; + if (x_shp.size() != SHAPE_SIZE || y_shp.size() != SHAPE_SIZE) { + MS_LOG(EXCEPTION) << "MatMul inputs should have the same dimension size and equal to 2."; + } + ValuePtr transpose_a_ptr = primitive->GetAttr("transpose_a"); + ValuePtr transpose_b_ptr = primitive->GetAttr("transpose_b"); + bool transpose_a = GetValue(transpose_a_ptr); + bool transpose_b = GetValue(transpose_b_ptr); + ShapeVector x_min_shape = x->shape()->min_shape(); + ShapeVector x_max_shape = x->shape()->max_shape(); + ShapeVector y_min_shape = y->shape()->min_shape(); + ShapeVector y_max_shape = y->shape()->max_shape(); + CheckMinMaxShape(x_shp, &x_min_shape, &x_max_shape); + CheckMinMaxShape(y_shp, &y_min_shape, &y_max_shape); + // Additional check for dynamic shape + // Last infer will be real shape values + bool x_not_dyn = std::all_of(x_shp.begin(), x_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); + bool y_not_dyn = std::all_of(y_shp.begin(), y_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); + if (x_not_dyn && y_not_dyn) { + auto x_col = x_shp[(transpose_a ? 0 : 1)]; + auto y_row = y_shp[(transpose_b ? 1 : 0)]; + if (x_col != y_row) { + MS_LOG(EXCEPTION) << "MatMul shape error, got x_col: " << x_col << ", y_row: " << y_row + << ". In MatMul x_col and y_row should be equal."; + } + } + ShapeVector ret_shape; + ShapeVector ret_min_shape; + ShapeVector ret_max_shape; + auto make_shape = [&transpose_a, &transpose_b](ShapeVector &output, const ShapeVector xshp, + const ShapeVector yshp) -> void { + output.push_back(xshp[(transpose_a ? 1 : 0)]); + output.push_back(yshp[(transpose_b ? 0 : 1)]); + return; + }; + make_shape(ret_shape, x_shp, y_shp); + make_shape(ret_min_shape, x_min_shape, y_min_shape); + make_shape(ret_max_shape, x_max_shape, y_max_shape); + TypePtr x_type = x->element()->GetTypeTrack(); + if (x_type->type_id() == TypeId::kNumberTypeInt8) { + x_type = kInt32; + } + if (primitive->HasAttr("cast_type")) { + auto out_type = primitive->GetAttr("cast_type"); + MS_EXCEPTION_IF_NULL(out_type); + if (!out_type->isa()) { + MS_EXCEPTION(ValueError) << "MatMul cast_type must be a `Type`"; + } + x_type = out_type->cast(); + } + return std::make_shared(x_type, std::make_shared(ret_shape, ret_min_shape, ret_max_shape)); +} + +AbstractBasePtr InferImplBatchMatMul(const AnalysisEnginePtr &, const PrimitivePtr &primitive, + const AbstractBasePtrList &args_spec_list) { + constexpr auto kBatchMatMulInputNum = 2; + const std::string op_name = primitive->name(); + CheckArgsSize(op_name, args_spec_list, kBatchMatMulInputNum); + auto x = CheckArg(op_name, args_spec_list, 0); + MS_EXCEPTION_IF_NULL(x); + MS_EXCEPTION_IF_NULL(x->shape()); + auto y = CheckArg(op_name, args_spec_list, 1); + MS_EXCEPTION_IF_NULL(y); + MS_EXCEPTION_IF_NULL(y->shape()); + auto x_shp = x->shape()->shape(); + auto y_shp = y->shape()->shape(); + constexpr size_t minimum_shape = 3; + if (x_shp.size() != y_shp.size() || x_shp.size() < minimum_shape) { + MS_LOG(EXCEPTION) + << "BatchMatMul input x, y should have the same dimension size and should be greater or equal to 3."; + } + ValuePtr transpose_a_ptr = primitive->GetAttr("transpose_a"); + ValuePtr transpose_b_ptr = primitive->GetAttr("transpose_b"); + bool transpose_a = GetValue(transpose_a_ptr); + bool transpose_b = GetValue(transpose_b_ptr); + ShapeVector x_min_shape = x->shape()->min_shape(); + ShapeVector x_max_shape = x->shape()->max_shape(); + ShapeVector y_min_shape = y->shape()->min_shape(); + ShapeVector y_max_shape = y->shape()->max_shape(); + CheckMinMaxShape(x_shp, &x_min_shape, &x_max_shape); + CheckMinMaxShape(y_shp, &y_min_shape, &y_max_shape); + // Additional check for dynamic shape + // Last infer will be real shape values + bool x_not_dyn = std::all_of(x_shp.begin(), x_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); + bool y_not_dyn = std::all_of(y_shp.begin(), y_shp.end(), [](int64_t value) { return value != Shape::SHP_ANY; }); + if (x_not_dyn && y_not_dyn) { + size_t offset = x_shp.size() - 2; + auto x_col = x_shp[offset + (transpose_a ? 0 : 1)]; + auto y_row = y_shp[offset + (transpose_b ? 1 : 0)]; + if (x_col != y_row) { + MS_LOG(EXCEPTION) << "BatchMatMul shape error, got x_col: " << x_col << ", y_row: " << y_row + << ". In BatchMatMul x_col and y_row should be equal."; + } + } + ShapeVector ret_shape; + ShapeVector ret_min_shape; + ShapeVector ret_max_shape; + auto make_shape = [&transpose_a, &transpose_b](ShapeVector &output, const ShapeVector xshp, + const ShapeVector yshp) -> void { + for (size_t i = 0; i < xshp.size() - 2; i++) { + if (xshp[i] != yshp[i]) { + if (xshp[i] > 0 && yshp[i] > 0) { + MS_LOG(EXCEPTION) << "BatchMatMul input x, y are different at index " << i << "."; + } + output.push_back(Shape::SHP_ANY); + } else { + output.push_back(xshp[i]); + } + } + const size_t bias = 2; + size_t offset = xshp.size() - bias; + output.push_back(xshp[offset + (transpose_a ? 1 : 0)]); + output.push_back(yshp[offset + (transpose_b ? 0 : 1)]); + return; + }; + make_shape(ret_shape, x_shp, y_shp); + make_shape(ret_min_shape, x_min_shape, y_min_shape); + make_shape(ret_max_shape, x_max_shape, y_max_shape); + TypePtr x_type = x->element()->GetTypeTrack(); + if (x_type->type_id() == TypeId::kNumberTypeInt8) { + x_type = kInt32; + } + if (primitive->HasAttr("cast_type")) { + auto out_type = primitive->GetAttr("cast_type"); + MS_EXCEPTION_IF_NULL(out_type); + if (!out_type->isa()) { + MS_EXCEPTION(ValueError) << "MatMul cast_type must be a `Type`"; + } + x_type = out_type->cast(); + } + return std::make_shared(x_type, std::make_shared(ret_shape, ret_min_shape, ret_max_shape)); +} + AbstractBasePtr InferImplLess(const AnalysisEnginePtr &, const PrimitivePtr &primitive, const AbstractBasePtrList &args_spec_list) { constexpr auto kLessInputNum = 2; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kLessInputNum); - - // Get the input tensors and their shapes. auto x = CheckArg(op_name, args_spec_list, 0); + MS_EXCEPTION_IF_NULL(x); MS_EXCEPTION_IF_NULL(x->shape()); ShapeVector x_shape = x->shape()->shape(); ShapeVector x_shape_min = x->shape()->min_shape().empty() ? x_shape : x->shape()->min_shape(); ShapeVector x_shape_max = x->shape()->max_shape().empty() ? x_shape : x->shape()->max_shape(); auto y = CheckArg(op_name, args_spec_list, 1); + MS_EXCEPTION_IF_NULL(y); MS_EXCEPTION_IF_NULL(y->shape()); ShapeVector y_shape = y->shape()->shape(); ShapeVector y_shape_min = y->shape()->min_shape().empty() ? y_shape : y->shape()->min_shape(); ShapeVector y_shape_max = y->shape()->max_shape().empty() ? y_shape : y->shape()->max_shape(); - // Compute the output shape by broadcasting the input shapes. auto out_shape = BroadcastShape(x_shape, y_shape); auto out_shape_min = BroadcastShape(x_shape_min, y_shape_min); auto out_shape_max = BroadcastShape(x_shape_max, y_shape_max); - auto output_type = std::make_shared(); - - // Create the output abstract tensor. return std::make_shared(output_type, std::make_shared(out_shape, out_shape_min, out_shape_max)); } @@ -328,39 +441,23 @@ AbstractBasePtr InferImplReal(const AnalysisEnginePtr &, const PrimitivePtr &pri // Inputs: one tensors. constexpr auto kRealInputNum = 1; const std::string op_name = primitive->name(); - - // Check the number of arguments to match expectations. CheckArgsSize(op_name, args_spec_list, kRealInputNum); - - // Get the input abstract base. AbstractBasePtr input_abs = args_spec_list[0]; - - // Check if the input is a tensor. auto input = dyn_cast(input_abs); - if (input == nullptr) { - // If the input is not a tensor, return a clone of the input abstract base. return input_abs->Clone(); } - - // Get the type of the input tensor. TypePtr input_type = input->element()->GetTypeTrack(); - TypePtr output_type = nullptr; - - // Determine the output type based on the input tensor type. if (input_type->type_id() == TypeId::kNumberTypeComplex64) { output_type = kFloat32; } else if (input_type->type_id() == TypeId::kNumberTypeComplex128) { output_type = kFloat64; } else { - // If the input type is not complex, return a clone of the input abstract base. return input_abs->Clone(); } - // Create the output abstract tensor. return std::make_shared(output_type, input->shape()); } - } // namespace abstract } // namespace mindspore -- 2.34.1 From b365ea5284a478ea15f77bb7ce0cc877790b6f91 Mon Sep 17 00:00:00 2001 From: iku50 Date: Tue, 3 Oct 2023 13:09:45 +0800 Subject: [PATCH 3/3] ok --- mindspore/core/abstract/utils.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mindspore/core/abstract/utils.cc b/mindspore/core/abstract/utils.cc index 05df2b504ec..4d7aa797bc6 100644 --- a/mindspore/core/abstract/utils.cc +++ b/mindspore/core/abstract/utils.cc @@ -31,7 +31,14 @@ const std::map type_map = { {kNumberTypeUInt16, 2}, {kNumberTypeUInt32, 4}, {kNumberTypeUInt64, 8}, {kNumberTypeFloat, 4}, {kNumberTypeFloat16, 2}, {kNumberTypeFloat32, 4}, {kNumberTypeFloat64, 8}, {kNumberTypeComplex64, 8}, {kNumberTypeComplex128, 16}}; - +ValuePtr ValueJoin(const ValuePtr &value1, const ValuePtr &value2) { + MS_EXCEPTION_IF_NULL(value1); + MS_EXCEPTION_IF_NULL(value2); + if (*value1 == *value2) { + return value1; + } + return kAnyValue; +} // Join two Type objects TypePtr TypeJoin(const TypePtr &type1, const TypePtr &type2) { MS_EXCEPTION_IF_NULL(type1); -- 2.34.1