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