* Copyright (c) 2025 Huawei Technologies Co., Ltd.
* This program is free software, you can redistribute it and/or modify it under the terms and conditions of
* CANN Open Software License Agreement Version 2.0 (the "License").
* Please refer to the License for details. You may not use this file except in compliance with the License.
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
* See LICENSE in the root of the software repository for the full text of the License.
*/
* @brief construct a graph using a simple way like:
* Function definition: AddOpDesc(op's name, op's type);
* SetInput(destination op's name , source op's name)
* GraphConstructor graph_constructor("graph1");
* graph_constructor.AddOpDesc("OutputName1", "OutputType1")
* .AddOpDesc("OutputName2", "OutputType1")
* .SetOutput("OutputName1")
* .SetInput("OutputName2:0", {"InputType_1:0"})
* .SetInput("OutputName2:1", {"InputType_1:0"})
* .SetInput("OutputName1:1", {"InputType_2:0"});
* .SetInput("OutputName1:0", {"InputType_3:0"});
*
*
* or (In this case, if there are multiple inputs, we will consider it as the
* input0, input1, input2... of the left parameter. Function definition:
* SetInput(dst_node_name, {src_node_name0, src_node_name_1...})):
* graph_constructor.AddOpDesc("OutputName1", "OutputType1")
* .AddOpDesc("OutputName2", "OutputType1")
* .SetOutput("OutputName1")
* .SetInput("OutputName2", {"InputType_1:0", "InputType_1:0"})
* .SetInput("OutputName1", {"InputType_3, InputType_2"});
*
*
* or (In the following case, the SetInput is its second version, which is
* defined as:
* SetInput({dst_node_name0, dst_node_name1}, src_node_name). That is the output
* of src node will be passed to multiple dst node.).
* graph_constructor.AddOpDesc("OutputName1", "OutputType1")
* .AddOpDesc("OutputName2", "OutputType1")
* .SetOutput("OutputName1")
* .SetInput({OutputName2:0, OutputName2:1}, "InputType_1:0")
* .SetInput("OutputName1", {"InputType_3, InputType_2"});
* p.s.:OutputName2 can be any node name.
*
*
* or :
* graph_constructor.SetOutput({"OutputType1_1", "OutputType1_2"})
* .SetInput("OutputName2:0", {"InputType_1:0", "InputType_1:0"})
* .SetInput("OutputName1", {"InputType_3, InputType_2"});
*
*
* The user can either use:
*
* AddOpDesc(op's name, op's type) to set the mapping relation of
* output op name and output op type
*
* or use:
*
* SetInput(destination op's name , source op's name) to set the connection
* between the source and destination in which the program will automatically
* extract the op type from the name which is in a correct format of:
* OpType + "_" + Integer1(node index) + ":" + Integer2(input or output index).
* If Integer1 is missing or "_" is missing, for example: Conv2D_:1 or
* Conv2D:1, we will consider it as Conv2D_0.
* And if Interger2 is missing or : is missing, for example: Conv2D: or Conv2D
* or Conv2D_2, we will consider it as Con2D_0:0, Con2D_0:0, Con2D_2:0
* seperately. *
*
* And for convenience, we will ignore the case of the node name.
*/
#ifndef LLT_FUSION_ENGINE_GRAPH_CONSTRUCTOR_GRAPH_CONSTRUCTOR_H_
#define LLT_FUSION_ENGINE_GRAPH_CONSTRUCTOR_GRAPH_CONSTRUCTOR_H_
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "common/util/op_info_util.h"
#include "common/graph_comm.h"
#include "string.h"
#include "ops_kernel_store/fe_ops_kernel_info_store.h"
using std::initializer_list;
using std::map;
using std::string;
using std::vector;
namespace fe {
#define GC_PRINT_SW (false)
#define GC_LOGD(...) \
if (GC_PRINT_SW) { \
D_FE_LOGD(FE_MODULE_NAME, __VA_ARGS__); \
} \
#define GC_LOGI(...) \
if (GC_PRINT_SW) { \
D_FE_LOGI(FE_MODULE_NAME, __VA_ARGS__); \
} \
enum ENUM_SRC_OR_DST {
SOURCE = 0,
DESTINATION = 1,
SOURCE_AND_DESTINATION = 2,
};
static ge::Format DEFAULT_FORMAT = ge::FORMAT_NCHW;
static ge::DataType DEFAULT_DTYPE = ge::DT_FLOAT;
static ge::GeShape DEFAULT_SHAPE = ge::GeShape({17,33,35,45});
* @ingroup fe
* @brief This struct contains the name, format, datatype,shape
* We assume the original data_type is the same as the current datatype,
* because we will not use that in FE. And the user only need to set the
* original shape because the current shape will be inferred by the original
* shape and format relation.
*/
ge::GeTensorDesc GetTensorDesc(const ge::OpDescPtr &op_desc_ptr,
const uint32_t &index, bool is_input);
void SetTensorDescIntAttr(const ge::OpDescPtr &op_desc_ptr,
const uint32_t &index, bool is_input,
const std::string &attr, const int64_t &attr_value);
struct DetailedNodeAndTensorInformation {
string name_;
ge::Format format_ = DEFAULT_FORMAT;
ge::DataType data_type_ = DEFAULT_DTYPE;
ge::GeShape original_shape_ = DEFAULT_SHAPE;
ge::Format original_format_ = DEFAULT_FORMAT;
DetailedNodeAndTensorInformation (const string& name_param) {
name_ = name_param;
format_ = DEFAULT_FORMAT;
original_format_ = DEFAULT_FORMAT;
data_type_ = DEFAULT_DTYPE;
original_shape_ = DEFAULT_SHAPE;
}
DetailedNodeAndTensorInformation (const string& name_param,
const ge::Format& format,
const ge::Format& original_format = DEFAULT_FORMAT,
const ge::DataType& dtype = DEFAULT_DTYPE,
const ge::GeShape& original_shape = DEFAULT_SHAPE) {
name_ = name_param;
format_ = format;
original_format_ = original_format;
data_type_ = dtype;
original_shape_ = original_shape;
}
};
static const std::map<ge::Format, uint32_t> FORMAT_NAME_MAP {
{ge::FORMAT_NDHWC, 5},
{ge::FORMAT_DHWCN, 5},
{ge::FORMAT_DHWNC, 5}
};
using ComputeGraphPtr = std::shared_ptr<ge::ComputeGraph>;
* Constructor a compute graph in a easy way
*/
class GraphConstructor {
public:
* @ingroup fe
* @brief description of Ops
*/
struct OpDesc {
string op_name;
ge::NodePtr node;
string type;
};
* @ingroup fe
* @brief It shows how to add data edges between nodes to nodes
*/
struct ConnectionInfo {
string op_name;
string type;
ge::NodePtr node;
int32_t starting_tensor_index;
};
using DetailedTensor = struct DetailedNodeAndTensorInformation;
GraphConstructor(ComputeGraphPtr& graph, const string& name = "",
const ge::Format& default_format = DEFAULT_FORMAT,
const ge::DataType& default_dtype = DEFAULT_DTYPE,
const ge::GeShape& default_shape = DEFAULT_SHAPE);
~GraphConstructor();
ge::NodePtr GetOp(const string &op_name);
* constructor.
* This step is not necessary, we can directly set the input and in the step
* of setting input, the program will automatically parse the op name and
* get the corresponding op type.
* @return GraphConstructor&
*/
GraphConstructor& AddOpDesc(const string& op_name,
const string& op_type,
const size_t& inputs_size = 0,
const size_t& outputs_size = 0);
GraphConstructor& AddOpDesc(const OpImplType& impl_type,
const string& pattern,
const string& op_name,
const string& op_type,
const size_t& inputs_size = 0,
const size_t& outputs_size = 0);
* nodes' name of this op. We will check whether the op_name is already in the
* op desc vector(ops_, each OpDesc struct contains a node pointer). If it's
* already in the op desc, we will create a new node and substitute the
* existing node with the new one and if not, we'll just create a new node.
* Then, add edge between source and dst. If the user specify the input or the
* output index, we will add enough input or output tensor and then link the
* specific anchor. Otherwise, the default tensor(anchor) index of output is 0
* and the default tensor(anchor) index of input is increasing by 1 from 0.
* op_name
* @return GraphConstructor&
*/
GraphConstructor& SetInputs(const DetailedTensor& dst_tensor,
const DetailedTensor& src_tensor);
GraphConstructor& SetInputs(const DetailedTensor& dst_tensor,
const vector<DetailedTensor>& multiple_src_tensors);
GraphConstructor& SetInputs(const string& dst_name,
const vector<string>& multiple_src_names);
GraphConstructor& SetInputs(const vector<string>& multiple_src_names);
GraphConstructor& SetInput(const string &dst_name, const string &src_name);
* tensor. The following function provides an ability to set the format */
GraphConstructor& SetInput(const string &dst_name, const string &src_name,
const ge::Format &format);
GraphConstructor& SetInput(const string &dst_name, const string &src_name,
const ge::Format &format,
const ge::Format &original_format);
GraphConstructor& SetInput(const string &dst_name, const string &src_name,
const ge::Format &format,
const ge::Format &original_format,
const vector<int64_t>& original_dims);
GraphConstructor& SetInput(const string &dst_name,
const ge::Format &dst_format,
const string &src_name,
const ge::Format &src_format);
GraphConstructor& SetInput(const string &dst_name,
const ge::Format &dst_format,
const ge::DataType &dst_dtype,
const string &src_name,
const ge::Format &src_format,
const ge::DataType &src_dtype);
GraphConstructor& SetInput(const string &dst_name,
const ge::Format &dst_format,
const string &src_name,
const ge::Format &src_format,
const ge::Format &dst_original_format);
GraphConstructor& SetInput(const string &dst_name,
const ge::Format &dst_format,
const string &src_name,
const ge::Format &src_format,
const ge::Format &dst_original_format,
const ge::Format &src_original_format);
GraphConstructor& SetInput(const string &dst_name,
const ge::Format &dst_format,
const string &src_name,
const ge::Format &src_format,
const ge::Format &dst_original_format,
const ge::Format &src_original_format,
const vector<int64_t>& dst_original_dims,
const vector<int64_t>& src_original_dims);
* of specific tensor. The following function provides an ability to set the
* format and shape*/
GraphConstructor& SetInput(const string &dst_name, const string &src_name,
const vector<int64_t>& dims,
const uint32_t& dst_or_src = SOURCE_AND_DESTINATION);
GraphConstructor& SetInput(const string &dst_name, const string &src_name,
const vector<int64_t>& dims,
const ge::Format &format,
const uint32_t& dst_or_src = SOURCE_AND_DESTINATION);
GraphConstructor &Attr(const string &node_name, const std::string &name, bool value);
GraphConstructor &Attr(const string &node_name, const std::string &name, int32_t value);
GraphConstructor &Attr(const string &node_name, const std::string &name, uint32_t value);
GraphConstructor &Attr(const string &node_name, const std::string &name, float value);
GraphConstructor &Attr(const string &node_name, const std::string &name, const std::vector<int32_t> &value);
GraphConstructor &Attr(const string &node_name, const std::string &name, const std::vector<uint32_t> &value);
GraphConstructor &Attr(const string &node_name, const std::string &name, const std::vector<int64_t> &value);
GraphConstructor &Attr(const string &node_name, const std::string &name, const char *value);
GraphConstructor &Attr(const std::string &name, bool value);
GraphConstructor &Attr(const std::string &name, int32_t value);
GraphConstructor &Attr(const std::string &name, uint32_t value);
GraphConstructor &Attr(const std::string &name, const std::vector<int32_t> &value);
GraphConstructor &Attr(const std::string &name, const std::vector<uint32_t> &value);
GraphConstructor &Attr(const std::string &name, const std::vector<int64_t> &value);
GraphConstructor &Attr(const std::string &name, const char *value);
static Status DumpGraph(const ge::ComputeGraphPtr& graph);
* otherwise return false. */
static bool CompareGraph(const ComputeGraphPtr& graph1, const ComputeGraphPtr& graph2);
static bool CompareNode(const ge::NodePtr & node1, const ge::NodePtr & node2);
static string GetInputString(const ge::NodePtr& node);
void GetNodeByName(const string& name, ge::NodePtr &node_out);
static ge::NodePtr GetNodeByName(const string& name, const ComputeGraphPtr& graph);
GraphConstructor& SetPattern(const string &optype);
GraphConstructor& SetFeImPlType(OpImplType impl_type);
GraphConstructor& SetTvmType();
template <class T>
GraphConstructor& SetExtAttr(string &&attr_name, const T &value);
private:
Status SetTensorDescInfo(ge::GeTensorDesc& tensor,
const ge::Format& original_format, const ge::DataType& data_type,
const ge::GeShape& shape, const ge::Format& format);
Status AddNewNodeIntoGraph(const string& op_type,
const string& op_real_name,
const size_t& size_of_new_tensors,
const DetailedTensor& tensor_info,
const bool& is_dst_node,
int32_t& tensor_index,
ge::NodePtr& new_node);
Status AddTensorIntoExistingNodes(
const size_t& size_of_new_tensors,
const DetailedTensor& tensor_info,
const bool& is_dst_node,
map<string, std::shared_ptr<OpDesc>>::iterator& iter,
int32_t& input_index);
* into connection info*/
Status ParseNodeNameAndAddNodeIntoGraph(
const DetailedTensor& dst_tensor,
const size_t& size_of_new_tensors,
bool is_dst_node, vector<ConnectionInfo>& connection_info_of_all_nodes);
Status AddEdges(
const vector<ConnectionInfo>& src_connection_info_of_all_nodes,
const vector<ConnectionInfo>& dst_connection_info_of_all_nodes);
*
* OpType_Integer1:Interer2
* Integer1 is the index of the node with same type.
* Integer2 is the index of the inputs or outputs.
*
* @return Status
*/
Status NodeNameParser(const string &name, string& op_type,
string& op_real_name, int32_t& input_or_output_index);
Status ReplaceNodeWithNewBode(ge::NodePtr& old_node, ge::NodePtr& new_node);
void SetGraph(ComputeGraphPtr graph);
ge::OpDescPtr CreateFunctionOp(vector<ge::NodePtr> &node_vec) const ;
Status AddFunctionNodeInputDesc(ge::OpDescPtr fus_op, vector<fe::FusionDataFlow> &fus_input_edge_list);
Status AddFunctionNodeOutputDesc(ge::OpDescPtr fus_op, vector<fe::FusionDataFlow> &fus_output_edge_list);
Status CreateFunctionOpSubGraph(ge::NodePtr &function_node,
std::vector<ge::NodePtr> &node_vec,
vector<fe::FusionDataFlow> &input_edge_list,
vector<fe::FusionDataFlow> &output_edge_list,
vector<fe::FusionDataFlow> &output_ctrl_edge_list);
Status TransSingleSubGraph(ge::ComputeGraph &graph, std::vector<ge::NodePtr> &node_vec);
private:
GraphConstructor(const GraphConstructor &) = default;
GraphConstructor &operator=(const GraphConstructor &) = default;
private:
ComputeGraphPtr graph_;
std::string graph_name_;
vector<std::shared_ptr<OpDesc>> ops_;
map<string, std::shared_ptr<OpDesc>> op_map_;
ge::NodePtr last_added_node_;
std::shared_ptr<fe::GraphComm> graph_comm_ptr_;
size_t sgt_graph_index_{0};
};
}
#endif