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