• 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 "kernel/graph_kernel/akg/akg_kernel_json_decoder.h"
17 
18 #include <memory>
19 #include "mindspore/core/ops/sequence_ops.h"
20 #include "mindspore/core/ops/array_ops.h"
21 #include "kernel/graph_kernel/graph_kernel_json_generator.h"
22 #include "kernel/framework_utils.h"
23 #include "backend/common/graph_kernel/adapter/fake_abstract_shape.h"
24 #include "include/backend/anf_runtime_algorithm.h"
25 #include "include/common/utils/anfalgo.h"
26 #include "include/common/debug/anf_ir_dump.h"
27 #include "frontend/operator/ops.h"
28 #include "ir/anf.h"
29 #include "ir/dtype.h"
30 #include "ir/func_graph.h"
31 #include "ir/graph_utils.h"
32 #include "ir/manager.h"
33 #include "ir/meta_tensor.h"
34 #include "pipeline/jit/ps/parse/data_converter.h"
35 #include "include/common/utils/python_adapter.h"
36 #include "include/backend/kernel_info.h"
37 #include "include/common/utils/convert_utils.h"
38 #include "include/common/utils/convert_utils_py.h"
39 #include "include/common/utils/utils.h"
40 #include "kernel/graph_kernel/graph_kernel_json_flags.h"
41 
42 namespace mindspore {
43 namespace kernel {
44 namespace {
45 using graphkernel::kJsonKeyAttr;
46 using graphkernel::kJsonKeyDataType;
47 using graphkernel::kJsonKeyFormat;
48 using graphkernel::kJsonKeyInputDesc;
49 using graphkernel::kJsonKeyName;
50 using graphkernel::kJsonKeyOpDesc;
51 using graphkernel::kJsonKeyOutputDesc;
52 using graphkernel::kJsonKeyProcess;
53 using graphkernel::kJsonKeyShape;
54 using graphkernel::kJsonKeyTensorName;
55 using graphkernel::kJsonKeyValue;
56 
57 constexpr auto kIsFeatureMapOutput = "IsFeatureMapOutput";
58 constexpr auto kIsFeatureMapInputList = "IsFeatureMapInputList";
59 
60 class CNodeDecoder {
61  public:
CNodeDecoder(std::map<std::string,AnfNodePtr> * nodes_map)62   explicit CNodeDecoder(std::map<std::string, AnfNodePtr> *nodes_map) : nodes_map_(*nodes_map) {}
63   ~CNodeDecoder() = default;
DecodeCNode(const nlohmann::json & cnode_json,const FuncGraphPtr & func_graph,kernel::Processor processor)64   CNodePtr DecodeCNode(const nlohmann::json &cnode_json, const FuncGraphPtr &func_graph, kernel::Processor processor) {
65     op_name_ = cnode_json[kJsonKeyName];
66     MS_LOG(DEBUG) << "Start decode cnode " << op_name_ << ", json: " << cnode_json;
67     // decode attrs.
68     if (!DecodeAttrs(cnode_json)) {
69       MS_LOG(ERROR) << "Decode attrs failed. op: " << op_name_ << ", json: " << cnode_json;
70       return nullptr;
71     }
72     if (!DecodeInputDesc(cnode_json, func_graph) || cnode_ == nullptr) {
73       MS_LOG(ERROR) << "Decode inputs failed. op: " << op_name_ << ", json: " << cnode_json;
74       return nullptr;
75     }
76     if (!DecodeOutputDesc(cnode_json, func_graph)) {
77       MS_LOG(ERROR) << "Decode outputs failed. op: " << op_name_ << ", json: " << cnode_json;
78       return nullptr;
79     }
80     CreateKernelInfo(processor);
81     CreateAbstract();
82     InitIOName(cnode_);
83     return cnode_;
84   }
85 
86  private:
ParseValue(const nlohmann::json & attr_json,const std::string & type) const87   ValuePtr ParseValue(const nlohmann::json &attr_json, const std::string &type) const {
88     if (type == "str") {
89       std::string value = attr_json[kJsonKeyValue];
90       if (op_name_ == "Cast" && attr_json[kJsonKeyName] == kAttrDstType) {
91         return StringToType(value);
92       }
93       return MakeValue(value);
94     } else if (type == "int") {
95       int64_t value = attr_json[kJsonKeyValue];
96       return MakeValue(value);
97     } else if (type == "bool") {
98       bool value = attr_json[kJsonKeyValue];
99       return MakeValue(value);
100     } else if (type == "float") {
101       float value = attr_json[kJsonKeyValue];
102       return MakeValue(value);
103     } else if (type == "listInt") {
104       std::vector<int64_t> value = attr_json[kJsonKeyValue];
105       return MakeValue(value);
106     } else if (type == "listStr") {
107       std::vector<std::string> value = attr_json[kJsonKeyValue];
108       return MakeValue(value);
109     } else {
110       MS_LOG(ERROR) << "Fail to parse attr " << attr_json[kJsonKeyName] << " in json, because its type: " << type
111                     << " is not in supported list: [str, int, bool, float, listInt, listStr]. json is: " << attr_json;
112       return nullptr;
113     }
114   }
115 
InitIOName(const CNodePtr & cnode) const116   void InitIOName(const CNodePtr &cnode) const {
117     auto primitive = GetCNodePrimitive(cnode);
118     MS_EXCEPTION_IF_NULL(primitive);
119     const auto &op_primc_fns = ops::OpPrimCRegister::GetInstance().GetPrimCMap();
120     auto const iter = op_primc_fns.find(primitive->name());
121     if (iter == op_primc_fns.end()) {
122       return;
123     }
124     auto prim = iter->second();
125     if (prim != nullptr) {
126       (void)primitive->AddAttr(kAttrInputNames, prim->GetAttr(kAttrInputNames));
127       (void)primitive->AddAttr(kAttrOutputNames, prim->GetAttr(kAttrOutputNames));
128     }
129   }
130 
DecodeAttrs(const nlohmann::json & attrs_json)131   bool DecodeAttrs(const nlohmann::json &attrs_json) {
132     MS_LOG(DEBUG) << "start decode attrs, " << attrs_json;
133     // attrs maybe empty
134     if (attrs_json.find(kJsonKeyAttr) == attrs_json.end() || attrs_json[kJsonKeyAttr].is_null()) {
135       return true;
136     }
137 
138     std::vector<nlohmann::json> attr_descs = attrs_json[kJsonKeyAttr];
139     for (const auto &attr_desc : attr_descs) {
140       std::string name = attr_desc[kJsonKeyName];
141       std::string type = attr_desc[kJsonKeyDataType];
142       auto value = ParseValue(attr_desc, type);
143       if (value == nullptr) {
144         return false;
145       }
146       cnode_attrs_[name] = value;
147     }
148     return true;
149   }
150 
DecodeInputDesc(const nlohmann::json & cnode_json,const FuncGraphPtr & func_graph)151   bool DecodeInputDesc(const nlohmann::json &cnode_json, const FuncGraphPtr &func_graph) {
152     auto primitive = CreatePrimitiveWithAttrs();
153     MS_EXCEPTION_IF_NULL(primitive);
154 
155     // collect inputs.
156     auto primitive_v = NewValueNode(primitive);
157     func_graph->AddValueNode(primitive_v);
158     std::vector<AnfNodePtr> inputs{primitive_v};
159     std::vector<nlohmann::json> input_descs = cnode_json[kJsonKeyInputDesc];
160     for (size_t i = 0; i < input_descs.size(); ++i) {
161       nlohmann::json input_desc = input_descs[i][0];
162       std::string name = input_desc[kJsonKeyTensorName];
163       if (input_desc.find(kJsonKeyValue) != input_desc.end()) {
164         auto value = DecodeValueNode(input_desc, func_graph);
165         if (value == nullptr) {
166           return false;
167         }
168         inputs.push_back(value);
169       } else if (nodes_map_.count(name) == 0) {
170         MS_LOG(ERROR) << "Input: " << name << " of: " << op_name_ << " not found.";
171         return false;
172       } else {
173         inputs.push_back(nodes_map_[name]);
174       }
175       input_formats_.push_back(input_desc[kJsonKeyFormat]);
176       input_types_.push_back(StringToTypeId(input_desc[kJsonKeyDataType]));
177       input_shapes_.push_back(input_desc[kJsonKeyShape]);
178     }
179     // new cnode.
180     cnode_ = func_graph->NewCNode(inputs);
181     func_graph->AddNode(cnode_);
182     return true;
183   }
184 
DecodeOutputDesc(const nlohmann::json & cnode_json,const FuncGraphPtr & func_graph)185   bool DecodeOutputDesc(const nlohmann::json &cnode_json, const FuncGraphPtr &func_graph) {
186     std::vector<nlohmann::json> output_descs = cnode_json[kJsonKeyOutputDesc];
187     if (output_descs.empty()) {
188       MS_LOG(ERROR) << "No outputs found in json: " << cnode_json << ", " << kJsonKeyOutputDesc << " is empty.";
189       return false;
190     } else if (output_descs.size() == 1) {
191       // single output.
192       nlohmann::json output_desc = output_descs[0];
193       output_formats_.push_back(output_desc[kJsonKeyFormat]);
194       output_types_.push_back(StringToTypeId(output_desc[kJsonKeyDataType]));
195       output_shapes_.push_back(output_desc[kJsonKeyShape]);
196       nodes_map_[output_desc[kJsonKeyTensorName]] = cnode_;
197     } else {
198       // multi outputs.
199       for (size_t j = 0; j < output_descs.size(); ++j) {
200         nlohmann::json output_desc = output_descs[j];
201         output_formats_.push_back(output_desc[kJsonKeyFormat]);
202         output_types_.push_back(StringToTypeId(output_desc[kJsonKeyDataType]));
203         output_shapes_.push_back(output_desc[kJsonKeyShape]);
204         auto get_item =
205           func_graph->NewCNode({NewValueNode(prim::kPrimTupleGetItem), cnode_, NewValueNode(SizeToLong(j))});
206         func_graph->AddNode(get_item);
207         nodes_map_[output_desc[kJsonKeyTensorName]] = get_item;
208       }
209     }
210     return true;
211   }
212 
CreateKernelInfo(kernel::Processor processor)213   void CreateKernelInfo(kernel::Processor processor) {
214     auto kernel_info = std::make_shared<device::KernelInfo>();
215     std::vector<size_t> feature_map_input_indexs;
216     // if the node only has the primitive(such as getNext) or the node's input has a feature map input
217     // then the node's output is a feature map output
218     const auto &inputs = cnode_->inputs();
219     for (size_t index = 1; index < inputs.size(); ++index) {
220       auto node = common::AnfAlgo::VisitKernel(inputs[index], 0);
221       if ((node.first)->isa<Parameter>()) {
222         auto parameter = (node.first)->cast<ParameterPtr>();
223         bool is_weight = common::AnfAlgo::IsParameterWeight(parameter);
224         kernel_info->set_feature_map_flag(!is_weight);
225         if (!is_weight) {
226           feature_map_input_indexs.push_back(index - 1);
227         }
228       }
229       if (AnfAlgo::IsFeatureMapOutput(node.first)) {
230         feature_map_input_indexs.push_back(index - 1);
231       }
232     }
233     if (common::AnfAlgo::GetCNodeName(cnode_) == prim::kPrimCast->name()) {
234       common::AnfAlgo::SetNodeAttr(kIsBackendCast, MakeValue(false), cnode_);
235     }
236     if (inputs.size() == 1 || !feature_map_input_indexs.empty()) {
237       kernel_info->set_feature_map_flag(true);
238     }
239     if (AnfUtils::IsRealCNodeKernel(cnode_)) {
240       common::AnfAlgo::SetNodeAttr(kIsFeatureMapOutput, MakeValue(kernel_info->is_feature_map()), cnode_);
241       common::AnfAlgo::SetNodeAttr(kIsFeatureMapInputList, MakeValue(feature_map_input_indexs), cnode_);
242     }
243     cnode_->set_kernel_info(kernel_info);
244     // create kernel_build_info.
245     auto builder = std::make_shared<kernel::KernelBuildInfo::KernelBuildInfoBuilder>();
246     builder->SetInputsFormat(input_formats_);
247     builder->SetInputsDeviceType(input_types_);
248     builder->SetOutputsFormat(output_formats_);
249     builder->SetOutputsDeviceType(output_types_);
250     builder->SetProcessor(processor);
251     builder->SetKernelType(KernelType::AKG_KERNEL);
252     builder->SetFusionType(kPatternOpaque);
253     AnfAlgo::SetSelectKernelBuildInfo(builder->Build(), cnode_.get());
254   }
255 
CreateAbstract() const256   void CreateAbstract() const {
257     auto shape = graphkernel::GetFakeAbstractShape(output_shapes_[0], output_formats_[0]);
258     auto abstract = std::make_shared<abstract::AbstractTensor>(TypeIdToType(output_types_[0]), shape);
259     cnode_->set_abstract(abstract);
260   }
261 
CreatePrimitiveWithAttrs() const262   PrimitivePtr CreatePrimitiveWithAttrs() const {
263     auto primitive = std::make_shared<Primitive>(op_name_);
264     for (const auto &attr : cnode_attrs_) {
265       (void)primitive->AddAttr(attr.first, attr.second);
266     }
267     return primitive;
268   }
269 
DecodeScalar(const nlohmann::json & scalar_json) const270   tensor::TensorPtr DecodeScalar(const nlohmann::json &scalar_json) const {
271     auto type_id = StringToTypeId(scalar_json[kJsonKeyDataType]);
272     if (type_id == TypeId::kNumberTypeFloat16) {
273       return std::make_shared<tensor::Tensor>(static_cast<float>(scalar_json[kJsonKeyValue]), kFloat16);
274     } else if (type_id == TypeId::kNumberTypeFloat32) {
275       return std::make_shared<tensor::Tensor>(static_cast<float>(scalar_json[kJsonKeyValue]), kFloat32);
276     } else if (type_id == TypeId::kNumberTypeInt32) {
277       return std::make_shared<tensor::Tensor>(static_cast<int64_t>(scalar_json[kJsonKeyValue]), kInt32);
278     } else if (type_id == TypeId::kNumberTypeInt64) {
279       return std::make_shared<tensor::Tensor>(static_cast<int64_t>(scalar_json[kJsonKeyValue]), kInt64);
280     }
281     MS_LOG(ERROR) << "Fail to parse scalar " << scalar_json[kJsonKeyValue]
282                   << " in json, because its type: " << scalar_json[kJsonKeyDataType]
283                   << " is not in supported list: [float16, float32, int32, int64]. json is: " << scalar_json;
284     return nullptr;
285   }
286 
DecodeValueNode(const nlohmann::json & value_json,const FuncGraphPtr & func_graph) const287   ValueNodePtr DecodeValueNode(const nlohmann::json &value_json, const FuncGraphPtr &func_graph) const {
288     MS_LOG(DEBUG) << "start decode value node, " << value_json;
289     auto tensor = DecodeScalar(value_json);
290     if (tensor == nullptr) {
291       return nullptr;
292     }
293     auto value_node = std::make_shared<ValueNode>(tensor);
294     value_node->set_abstract(tensor->ToAbstract());
295     // create kernel_info fo new value node.
296     auto kernel_info = std::make_shared<device::KernelInfo>();
297     value_node->set_kernel_info(kernel_info);
298     // create kernel_build_info for new value node.
299     auto builder = std::make_shared<kernel::KernelBuildInfo::KernelBuildInfoBuilder>();
300     // layout info.
301     builder->SetOutputsFormat(std::vector<std::string>{value_json[kJsonKeyFormat]});
302     builder->SetOutputsDeviceType(std::vector<TypeId>{StringToTypeId(value_json[kJsonKeyDataType])});
303     AnfAlgo::SetSelectKernelBuildInfo(builder->Build(), value_node.get());
304     func_graph->AddValueNode(value_node);
305     const int kDebugLevel = 2;
306     MS_LOG(DEBUG) << "decode value node success, " << value_node->DebugString(kDebugLevel);
307     return value_node;
308   }
309 
310   std::map<std::string, AnfNodePtr> &nodes_map_;
311   std::map<std::string, ValuePtr> cnode_attrs_;
312   std::vector<std::string> input_formats_;
313   std::vector<std::string> output_formats_;
314   std::vector<TypeId> input_types_;
315   std::vector<TypeId> output_types_;
316   std::vector<ShapeVector> input_shapes_;
317   std::vector<ShapeVector> output_shapes_;
318   CNodePtr cnode_{nullptr};
319   std::string op_name_;
320 };
321 }  // namespace
322 
DecodeParameter(const nlohmann::json & parameter_json,const FuncGraphPtr & func_graph)323 ParameterPtr AkgKernelJsonDecoder::DecodeParameter(const nlohmann::json &parameter_json,
324                                                    const FuncGraphPtr &func_graph) {
325   MS_LOG(DEBUG) << "start decode parameter, " << parameter_json;
326   ParameterPtr new_parameter = func_graph->add_parameter();
327   std::string name = parameter_json[kJsonKeyTensorName];
328   new_parameter->set_name(name);
329   std::string format = parameter_json[kJsonKeyFormat];
330   TypeId dtype = StringToTypeId(parameter_json[kJsonKeyDataType]);
331   ShapeVector shape = graphkernel::GetFakeAbstractShape(parameter_json[kJsonKeyShape], format);
332   auto abstract = std::make_shared<abstract::AbstractTensor>(TypeIdToType(dtype), shape);
333   new_parameter->set_abstract(abstract);
334   auto kernel_info = std::make_shared<device::KernelInfo>();
335   new_parameter->set_kernel_info(kernel_info);
336   auto builder = std::make_shared<kernel::KernelBuildInfo::KernelBuildInfoBuilder>();
337   builder->SetOutputsFormat(std::vector<std::string>{format});
338   builder->SetOutputsDeviceType(std::vector<TypeId>{dtype});
339   AnfAlgo::SetSelectKernelBuildInfo(builder->Build(), new_parameter.get());
340   nodes_map_[name] = new_parameter;
341   return new_parameter;
342 }
343 
DecodeCNode(const nlohmann::json & cnode_json,const FuncGraphPtr & func_graph,const std::string & processor)344 CNodePtr AkgKernelJsonDecoder::DecodeCNode(const nlohmann::json &cnode_json, const FuncGraphPtr &func_graph,
345                                            const std::string &processor) {
346   CNodeDecoder decoder(&nodes_map_);
347   Processor p = kernel::GetProcessor(processor);
348   return decoder.DecodeCNode(cnode_json, func_graph, p);
349 }
350 
DecodeOutput(const std::vector<nlohmann::json> & output_descs,const FuncGraphPtr & func_graph)351 AnfNodePtr AkgKernelJsonDecoder::DecodeOutput(const std::vector<nlohmann::json> &output_descs,
352                                               const FuncGraphPtr &func_graph) {
353   std::vector<AnfNodePtr> outputs{NewValueNode(prim::kPrimMakeTuple)};
354   AbstractBasePtrList output_abstract_list;
355   for (const auto &output_desc : output_descs) {
356     std::string name = output_desc[kJsonKeyTensorName];
357     if (nodes_map_.count(name) == 0) {
358       MS_LOG(ERROR) << "Output: " << name << " of graph not found.";
359       return nullptr;
360     }
361     outputs.push_back(nodes_map_[name]);
362     output_abstract_list.push_back(outputs.back()->abstract());
363   }
364   const int kDualOutputs = 2;
365   if (outputs.size() == kDualOutputs) {
366     func_graph->set_output(outputs[1]);
367   } else {
368     auto output = func_graph->NewCNode(outputs);
369     output->set_abstract(std::make_shared<abstract::AbstractTuple>(output_abstract_list));
370     func_graph->AddNode(output);
371     func_graph->set_output(output);
372   }
373   return func_graph->output();
374 }
375 
DecodeFusedNodes(const nlohmann::json & kernel_json)376 FuncGraphPtr AkgKernelJsonDecoder::DecodeFusedNodes(const nlohmann::json &kernel_json) {
377   MS_LOG(DEBUG) << "Start decoding json: " << kernel_json;
378   nodes_map_.clear();
379   auto graph = std::make_shared<FuncGraph>();
380 
381   // decode parameters.
382   std::vector<nlohmann::json> input_descs = kernel_json[kJsonKeyInputDesc];
383   if (input_descs.empty()) {
384     MS_LOG(ERROR) << "Error decoding parameter: no inputs for graph. Because " << kJsonKeyInputDesc
385                   << " is empty in json: " << kernel_json;
386     return nullptr;
387   }
388   for (size_t i = 0; i < input_descs.size(); ++i) {
389     std::vector<nlohmann::json> input_desc = input_descs[i];
390     auto parameter = DecodeParameter(input_desc[0], graph);
391     MS_EXCEPTION_IF_NULL(parameter);
392   }
393   MS_LOG(DEBUG) << "Decode parameters successfully.";
394 
395   // decode cnodes in graph.
396   std::vector<nlohmann::json> op_node_descs = kernel_json[kJsonKeyOpDesc];
397   if (op_node_descs.empty()) {
398     MS_LOG(ERROR) << "Error decoding cnodes: no cnodes for graph. Because " << kJsonKeyOpDesc
399                   << " is empty in json: " << kernel_json;
400     return nullptr;
401   }
402   for (const auto &op_desc : op_node_descs) {
403     auto op_node = DecodeCNode(op_desc, graph, kernel_json[kJsonKeyProcess]);
404     if (op_node == nullptr) {
405       return nullptr;
406     }
407   }
408   MS_LOG(DEBUG) << "Decode cnodes successfully.";
409 
410   // decode outputs of graph.
411   std::vector<nlohmann::json> output_descs = kernel_json[kJsonKeyOutputDesc];
412   if (output_descs.empty()) {
413     MS_LOG(ERROR) << "Error decoding outputs: no outputs for graph. Because " << kJsonKeyOutputDesc
414                   << " is empty in json: " << kernel_json;
415     return nullptr;
416   }
417   auto output = DecodeOutput(output_descs, graph);
418   if (output == nullptr) {
419     return nullptr;
420   }
421   MS_LOG(DEBUG) << "Decode json successfully, json: " << kernel_json;
422   return graph;
423 }
424 
DecodeFusedNodes(const std::string & kernel_json_str)425 FuncGraphPtr AkgKernelJsonDecoder::DecodeFusedNodes(const std::string &kernel_json_str) {
426   auto kernel_json = nlohmann::json::parse(kernel_json_str);
427   return DecodeFusedNodes(kernel_json);
428 }
429 }  // namespace kernel
430 }  // namespace mindspore
431