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 ¶meter_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