• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020-2022 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "backend/common/graph_kernel/graph_kernel_helper.h"
17 
18 #include <algorithm>
19 #include <map>
20 #include <set>
21 #include <tuple>
22 #include <utility>
23 
24 #include "backend/common/graph_kernel/adapter/fake_abstract_shape.h"
25 #include "backend/common/graph_kernel/core/graph_builder.h"
26 #include "backend/common/graph_kernel/graph_kernel_flags.h"
27 #include "base/base.h"
28 #include "include/backend/anf_runtime_algorithm.h"
29 #include "include/common/utils/utils.h"
30 #include "include/common/utils/anfalgo.h"
31 #include "include/common/utils/python_adapter.h"
32 #include "ir/tensor.h"
33 #include "ir/func_graph.h"
34 #include "ir/func_graph_cloner.h"
35 #include "kernel/framework_utils.h"
36 #include "kernel/graph_kernel/akg/akg_kernel_json_decoder.h"
37 #include "kernel/graph_kernel/graph_kernel_json_generator.h"
38 #include "kernel/kernel.h"
39 #include "mindspore/core/ops/sequence_ops.h"
40 #include "pipeline/jit/ps/action.h"
41 #include "utils/hash_set.h"
42 #include "utils/check_convert_utils.h"
43 
44 namespace mindspore::graphkernel {
45 namespace {
46 constexpr auto kPatternOpaque = "Opaque";
GenJson(const AnfNodePtrList & op_nodes,const std::pair<AnfNodePtrList,AnfNodePtrList> & in_and_out,const DumpOption & dump_option,nlohmann::json * op_desc,std::map<std::string,AnfNodePtr> * address_node_map=nullptr)47 bool GenJson(const AnfNodePtrList &op_nodes, const std::pair<AnfNodePtrList, AnfNodePtrList> &in_and_out,
48              const DumpOption &dump_option, nlohmann::json *op_desc,
49              std::map<std::string, AnfNodePtr> *address_node_map = nullptr) {
50   GraphKernelJsonGenerator graph_kernel_json_generator(dump_option);
51   if (!graph_kernel_json_generator.CollectFusedJson(op_nodes, in_and_out.first, in_and_out.second)) {
52     MS_LOG(ERROR) << "Collect json desc failed.";
53     return false;
54   }
55 
56   *op_desc = graph_kernel_json_generator.kernel_json();
57   if (address_node_map != nullptr) {
58     *address_node_map = graph_kernel_json_generator.address_node_map();
59   }
60   std::string fused_name;
61   (void)std::for_each(op_nodes.begin(), op_nodes.end(), [&fused_name](const AnfNodePtr &node) {
62     (void)fused_name.append(common::AnfAlgo::GetCNodeName(node)).append("_");
63   });
64   MS_LOG(DEBUG) << "Collect fusion json: " << fused_name;
65   return true;
66 }
67 }  // namespace
68 
GetOutputAbstract(const AnfNodePtr & node,size_t output_idx)69 AbstractBasePtr GetOutputAbstract(const AnfNodePtr &node, size_t output_idx) {
70   auto out_spec = node->abstract();
71   if (out_spec->isa<abstract::AbstractTuple>()) {
72     return out_spec->cast<abstract::AbstractTuplePtr>()->elements()[output_idx];
73   }
74   return out_spec;
75 }
76 
77 // Build for new node, processor comes from context
BuildSelectKernelBuildInfo(const std::vector<std::string> & inputs_format,const std::vector<TypeId> & inputs_type,const std::vector<std::string> & output_formats,const std::vector<TypeId> & output_types)78 kernel::KernelBuildInfoPtr BuildSelectKernelBuildInfo(const std::vector<std::string> &inputs_format,
79                                                       const std::vector<TypeId> &inputs_type,
80                                                       const std::vector<std::string> &output_formats,
81                                                       const std::vector<TypeId> &output_types) {
82   return BuildSelectKernelBuildInfo(inputs_format, inputs_type, output_formats, output_types,
83                                     kernel::GetProcessorFromContext());
84 }
85 
86 // Build for new node with given processor
BuildSelectKernelBuildInfo(const std::vector<std::string> & inputs_format,const std::vector<TypeId> & inputs_type,const std::vector<std::string> & output_formats,const std::vector<TypeId> & output_types,const kernel::Processor & processor)87 kernel::KernelBuildInfoPtr BuildSelectKernelBuildInfo(const std::vector<std::string> &inputs_format,
88                                                       const std::vector<TypeId> &inputs_type,
89                                                       const std::vector<std::string> &output_formats,
90                                                       const std::vector<TypeId> &output_types,
91                                                       const kernel::Processor &processor) {
92   kernel::KernelBuildInfo::KernelBuildInfoBuilder graph_info_builder;
93   graph_info_builder.SetInputsFormat(inputs_format);
94   graph_info_builder.SetInputsDeviceType(inputs_type);
95   graph_info_builder.SetOutputsFormat(output_formats);
96   graph_info_builder.SetOutputsDeviceType(output_types);
97   graph_info_builder.SetProcessor(processor);
98   graph_info_builder.SetKernelType(KernelType::AKG_KERNEL);
99   graph_info_builder.SetFusionType(kPatternOpaque);
100   return graph_info_builder.Build();
101 }
102 
AnfToJsonDesc(const AnfNodePtrList & nodes,const DumpOption & dump_option,nlohmann::json * op_desc,std::map<std::string,AnfNodePtr> * address_node_map)103 bool AnfToJsonDesc(const AnfNodePtrList &nodes, const DumpOption &dump_option, nlohmann::json *op_desc,
104                    std::map<std::string, AnfNodePtr> *address_node_map) {
105   MS_EXCEPTION_IF_NULL(op_desc);
106   if (nodes.empty()) {
107     MS_LOG(ERROR) << "Input nodes is empty.";
108     return false;
109   }
110   bool has_graph_kernel = std::any_of(nodes.begin(), nodes.end(), common::AnfAlgo::IsGraphKernel);
111   bool is_single_graph_kernel = has_graph_kernel && nodes.size() == 1;
112 
113   FuncGraphPtr fg;
114   AnfNodePtrList op_nodes;
115   AnfNodePtrList inputs;
116   AnfNodePtrList outputs;
117   if (is_single_graph_kernel) {
118     fg = common::AnfAlgo::GetCNodeFuncGraphPtr(nodes[0]);
119     kernel::GetValidKernelNodes(fg, &op_nodes, &inputs, &outputs);
120   } else if (!has_graph_kernel) {
121     std::tie(fg, inputs, outputs) = BuildGraphFromNodes(nodes);
122     op_nodes = nodes;
123   } else {
124     // When there are basic and composite ops, the composite ops should be inline to the basic ones' graph,
125     // so a new graph generation should be done (because they may in the main graph!).
126     // If address_node_map is wanted, we should map the new node in new graph to the old nodes. But... not support now.
127     MS_LOG(EXCEPTION) << "No support mixed with basic and composite ops now!";
128   }
129   std::pair<AnfNodePtrList, AnfNodePtrList> in_and_out = std::make_pair(inputs, outputs);
130   return GenJson(op_nodes, in_and_out, dump_option, op_desc, address_node_map);
131 }
132 
AnfToJsonDesc(const AnfNodePtrList & nodes,const DumpOption & dump_option,nlohmann::json * op_desc)133 bool AnfToJsonDesc(const AnfNodePtrList &nodes, const DumpOption &dump_option, nlohmann::json *op_desc) {
134   MS_EXCEPTION_IF_NULL(op_desc);
135   if (nodes.empty()) {
136     MS_LOG(ERROR) << "Input nodes is empty.";
137     return false;
138   }
139 
140   FuncGraphPtr fg;
141 
142   if (nodes.size() == 1 && common::AnfAlgo::IsGraphKernel(nodes[0])) {
143     fg = common::AnfAlgo::GetCNodeFuncGraphPtr(nodes[0]);
144   } else {
145     std::tie(fg, std::ignore, std::ignore) = BuildSingleGraphFromNodes(nodes);
146   }
147 
148   AnfNodePtrList op_nodes;
149   AnfNodePtrList inputs;
150   AnfNodePtrList outputs;
151   kernel::GetValidKernelNodes(fg, &op_nodes, &inputs, &outputs);
152 
153   auto mng = fg->manager();
154   if (mng == nullptr) {
155     mng = Manage(fg, false);
156     fg->set_manager(mng);
157   }
158   std::pair<AnfNodePtrList, AnfNodePtrList> in_and_out = std::make_pair(inputs, outputs);
159   return GenJson(op_nodes, in_and_out, dump_option, op_desc);
160 }
161 
AnfToJsonDesc(const std::vector<AnfNodePtrList> & graphs,const DumpOption & dump_option,nlohmann::json * op_desc)162 bool AnfToJsonDesc(const std::vector<AnfNodePtrList> &graphs, const DumpOption &dump_option, nlohmann::json *op_desc) {
163   MS_EXCEPTION_IF_NULL(op_desc);
164   std::vector<nlohmann::json> graphs_desc;
165   for (auto const &graph_nodes : graphs) {
166     nlohmann::json desc;
167     if (!AnfToJsonDesc(graph_nodes, dump_option, &desc)) {
168       MS_LOG(ERROR) << "Collect json desc failed.";
169       return false;
170     }
171     graphs_desc.push_back(desc);
172   }
173   if (graphs_desc.empty()) {
174     MS_LOG(ERROR) << "Collect zero json desc.";
175     return false;
176   }
177 
178   if (graphs_desc.size() > 1) {
179     nlohmann::json op_json_desc;
180     op_json_desc[kJsonKeyMultiGraph] = true;
181     op_json_desc[kJsonKeyGraphDesc] = graphs_desc;
182     *op_desc = op_json_desc;
183     return true;
184   }
185 
186   *op_desc = graphs_desc[0];
187   return true;
188 }
189 
JsonDescToAnf(const std::string & json_desc)190 FuncGraphPtr JsonDescToAnf(const std::string &json_desc) {
191   kernel::AkgKernelJsonDecoder akg_kernel_json_decoder;
192   auto fg = akg_kernel_json_decoder.DecodeFusedNodes(json_desc);
193   if (fg == nullptr) {
194     MS_LOG(ERROR) << "Akg decode json to graph failed. json is: " << json_desc;
195     return nullptr;
196   }
197   return fg;
198 }
199 
GetFormat(const AnfNodePtr & node)200 std::string GetFormat(const AnfNodePtr &node) { return AnfAlgo::GetOutputFormat(node, 0); }
201 
GetType(const AnfNodePtr & node)202 TypePtr GetType(const AnfNodePtr &node) {
203   const auto &abstract = node->abstract();
204   auto type = abstract->BuildType();
205   MS_EXCEPTION_IF_NULL(type);
206   return type;
207 }
208 
GetShape(const AnfNodePtr & node)209 ShapeVector GetShape(const AnfNodePtr &node) {
210   auto abstract = node->abstract();
211   MS_EXCEPTION_IF_NULL(abstract);
212   auto shape = abstract->GetShapeTrack();
213   if (shape == nullptr) {
214     MS_LOG(EXCEPTION) << "The shape of node " << node->fullname_with_scope() << " is nullptr";
215   } else if (!shape->isa<abstract::Shape>()) {
216     MS_LOG(EXCEPTION) << "The shape of node " << node->fullname_with_scope() << " should be of type Shape, but got "
217                       << shape->ToString();
218   }
219   auto shape_vec = shape->cast<abstract::ShapePtr>()->shape();
220   if (shape_vec.empty()) {
221     shape_vec.push_back(1);
222   }
223   return shape_vec;
224 }
225 
GetDeviceShape(const AnfNodePtr & node)226 ShapeVector GetDeviceShape(const AnfNodePtr &node) {
227   ShapeVector res_device_shape = AnfAlgo::GetOutputDeviceShape(node, 0);
228   return res_device_shape.empty() ? ShapeVector({1}) : res_device_shape;
229 }
230 
GetReduceAxis(const AnfNodePtr & node)231 std::vector<int64_t> GetReduceAxis(const AnfNodePtr &node) {
232   auto cnode = node->cast<CNodePtr>();
233   MS_EXCEPTION_IF_NULL(cnode);
234   auto axis_node = cnode->input(kIndex2)->cast<ValueNodePtr>();
235   MS_EXCEPTION_IF_NULL(axis_node);
236 
237   std::vector<int64_t> axis;
238   auto &v = axis_node->value();
239   if (v->isa<ValueList>() || v->isa<ValueTuple>()) {
240     auto vec = v->isa<ValueList>() ? v->cast<ValueListPtr>()->value() : v->cast<ValueTuplePtr>()->value();
241     for (auto value : vec) {
242       if (value->isa<Int64Imm>()) {
243         axis.push_back(GetValue<int64_t>(value));
244       } else {
245         MS_LOG(EXCEPTION) << "Element in attribute 'axis' should be of type int64 in node "
246                           << node->fullname_with_scope();
247       }
248     }
249   } else if (v->isa<Int64Imm>()) {
250     axis.push_back(GetValue<int64_t>(v));
251   } else if (v->isa<tensor::Tensor>()) {
252     axis = CheckAndConvertUtils::CheckTensorIntValue("axis", v, "ReduceSum");
253   } else {
254     MS_LOG(EXCEPTION) << "Attribute 'axis' should be a list or tuple in node " << node->fullname_with_scope();
255   }
256 
257   return axis;
258 }
259 
260 // Deprecated. use GkUtils::NewRealCNode
CreateCNode(const std::vector<AnfNodePtr> & inputs,const FuncGraphPtr & func_graph,const DataInfo & out_info,bool use_fake_abstract)261 CNodePtr CreateCNode(const std::vector<AnfNodePtr> &inputs, const FuncGraphPtr &func_graph, const DataInfo &out_info,
262                      bool use_fake_abstract) {
263   // Limitation: 1. Node's attributes should be set out of this function; 2. only one output.
264   MS_EXCEPTION_IF_NULL(out_info.type);
265   auto out_type = out_info.type;
266   if (auto otype = out_info.type->cast<TensorTypePtr>(); otype != nullptr) {
267     out_type = otype->element();
268   }
269 
270   // Create CNode.
271   auto cnode = func_graph->NewCNode(inputs);
272   MS_EXCEPTION_IF_NULL(cnode);
273 
274   // Setup abstract.
275   if (use_fake_abstract) {
276     auto abs_shape = GetFakeAbstractShape(out_info.shape, out_info.format);
277     auto abs_tensor = std::make_shared<abstract::AbstractTensor>(out_type, abs_shape);
278     cnode->set_abstract(abs_tensor);
279   } else {
280     auto abs_tensor = std::make_shared<abstract::AbstractTensor>(out_type, out_info.shape);
281     cnode->set_abstract(abs_tensor);
282   }
283 
284   // Setup kernel info.
285   auto kernel_info = std::make_shared<device::KernelInfo>();
286   cnode->set_kernel_info(kernel_info);
287   std::vector<size_t> feature_map_input_indexs;
288   kernel_info->set_feature_map_flag(false);
289   for (size_t i = 1; i < inputs.size(); ++i) {
290     if (AnfAlgo::IsFeatureMapOutput(inputs[i])) {
291       kernel_info->set_feature_map_flag(true);
292       feature_map_input_indexs.push_back(i);
293     }
294   }
295   if (inputs.size() == 1) {
296     kernel_info->set_feature_map_flag(true);
297   }
298   if (AnfUtils::IsRealKernel(cnode)) {
299     // if the node only has the primitive(such as getNext) or the node's input has a feature map input
300     // then the node's output is a feature map output
301     SetNodeAttrSafely(kIsFeatureMapOutput, MakeValue(kernel_info->is_feature_map()), cnode);
302     SetNodeAttrSafely(kIsFeatureMapInputList, MakeValue(feature_map_input_indexs), cnode);
303   }
304 
305   // Setup kernel build info.
306   std::vector<std::string> input_formats;
307   std::vector<TypeId> input_types;
308   for (size_t i = 1; i < inputs.size(); ++i) {
309     auto kernel_with_index = common::AnfAlgo::VisitKernel(inputs[i], 0);
310     auto input_format = AnfAlgo::GetOutputFormat(kernel_with_index.first, kernel_with_index.second);
311     input_formats.push_back(input_format);
312     auto input_type = AnfAlgo::GetOutputDeviceDataType(kernel_with_index.first, kernel_with_index.second);
313     input_types.push_back(input_type);
314   }
315 
316   std::vector<std::string> output_formats = {out_info.format};
317   std::vector<TypeId> output_types = {out_type->type_id()};
318 
319   kernel::KernelBuildInfo::KernelBuildInfoBuilder info_builder;
320   info_builder.SetInputsFormat(input_formats);
321   info_builder.SetInputsDeviceType(input_types);
322   info_builder.SetOutputsFormat(output_formats);
323   info_builder.SetOutputsDeviceType(output_types);
324   info_builder.SetProcessor(kernel::GetProcessorFromContext());
325   info_builder.SetKernelType(KernelType::AKG_KERNEL);
326   info_builder.SetFusionType(kPatternOpaque);
327   auto selected_info = info_builder.Build();
328   AnfAlgo::SetSelectKernelBuildInfo(selected_info, cnode.get());
329 
330   func_graph->AddNode(cnode);
331   return cnode;
332 }
333 
SetNodeAttrSafely(const std::string & key,const ValuePtr & value,const AnfNodePtr & node)334 void SetNodeAttrSafely(const std::string &key, const ValuePtr &value, const AnfNodePtr &node) {
335   common::AnfAlgo::SetNodeAttrSafely(key, value, node);
336 }
337 
IsBufferStitchNode(const AnfNodePtr & node)338 bool IsBufferStitchNode(const AnfNodePtr &node) {
339   auto cnode = node->cast<CNodePtr>();
340   MS_EXCEPTION_IF_NULL(cnode);
341   auto input = cnode->input(kAnfPrimitiveIndex);
342   if (!IsValueNode<FuncGraph>(input)) {
343     return common::AnfAlgo::HasNodeAttr(kAttrStitch, cnode);
344   }
345 
346   auto func_graph = GetValueNode<FuncGraphPtr>(input);
347   MS_EXCEPTION_IF_NULL(func_graph);
348   AnfNodePtrList sub_nodes;
349   kernel::GetValidKernelNodes(func_graph, &sub_nodes);
350   for (auto sub_node : sub_nodes) {
351     auto sub_cnode = sub_node->cast<CNodePtr>();
352     MS_EXCEPTION_IF_NULL(sub_cnode);
353     if (common::AnfAlgo::HasNodeAttr(kAttrStitch, sub_cnode)) {
354       return true;
355     }
356   }
357 
358   return false;
359 }
360 
CheckDefaultFormat(const AnfNodePtr & node)361 bool CheckDefaultFormat(const AnfNodePtr &node) {
362   MS_EXCEPTION_IF_NULL(node);
363   if (node->kernel_info() == nullptr) {
364     return true;
365   }
366   auto build_info = AnfAlgo::GetSelectKernelBuildInfo(node);
367   if (build_info == nullptr) {
368     return true;
369   }
370   auto inputs_format = build_info->GetAllInputFormats();
371   if (!std::all_of(inputs_format.begin(), inputs_format.end(),
372                    [](const std::string &format) { return IsOneOfDefaultFormat(format); })) {
373     return false;
374   }
375   auto outputs_format = build_info->GetAllOutputFormats();
376   return std::all_of(outputs_format.begin(), outputs_format.end(),
377                      [](const std::string &format) { return IsOneOfDefaultFormat(format); });
378 }
379 
CreateTensorValueNode(const DataInfo & info,void * value_ptr,size_t data_length)380 ValueNodePtr CreateTensorValueNode(const DataInfo &info, void *value_ptr, size_t data_length) {
381   // Create tensor value.
382   if (info.type == nullptr) {
383     MS_LOG(EXCEPTION) << "Data type can not be nullptr when creating scalar tensor!";
384   }
385 
386   tensor::TensorPtr tensor = std::make_shared<tensor::Tensor>(info.type->type_id(), info.shape);
387   MS_EXCEPTION_IF_NULL(tensor);
388   tensor::DeviceInfo device_info{info.format, info.type};
389   tensor->set_device_info(device_info);
390   auto data_ptr = tensor->data_c();
391   MS_EXCEPTION_IF_NULL(data_ptr);
392   auto ret_code = memcpy_s(data_ptr, static_cast<size_t>(tensor->data().nbytes()), value_ptr, data_length);
393   if (ret_code != EOK) {
394     MS_LOG(EXCEPTION) << "Failed to copy data into scalar tensor, memcpy_s errorno: " << ret_code;
395   }
396 
397   // Create value node.
398   ValueNodePtr new_value_node = std::make_shared<ValueNode>(tensor);
399   new_value_node->set_abstract(tensor->ToAbstract());
400   auto kernel_info = std::make_shared<device::KernelInfo>();
401   new_value_node->set_kernel_info(kernel_info);
402   auto kernel_build_info_builder = std::make_shared<kernel::KernelBuildInfo::KernelBuildInfoBuilder>();
403   kernel_build_info_builder->SetOutputsFormat(std::vector<std::string>{info.format});
404   std::vector<TypeId> types = {info.type->type_id()};
405   kernel_build_info_builder->SetOutputsDeviceType(types);
406   AnfAlgo::SetSelectKernelBuildInfo(kernel_build_info_builder->Build(), new_value_node.get());
407 
408   return new_value_node;
409 }
410 }  // namespace mindspore::graphkernel
411