1 /**
2 * Copyright 2023 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
17 #include "tools/optimizer/graph/miniaturization_pass.h"
18
19 #include <functional>
20 #include <vector>
21 #include <memory>
22 #include "nnacl/op_base.h"
23 #include "ops/op_utils.h"
24 #include "ops/fill.h"
25 #include "src/common/utils.h"
26 #include "tools/optimizer/common/gllo_utils.h"
27 #include "utils/check_convert_utils.h"
28
29 namespace mindspore::opt {
GetTensorFromNode(const AnfNodePtr & node)30 static inline tensor::TensorPtr GetTensorFromNode(const AnfNodePtr &node) {
31 MS_ASSERT(node != nullptr);
32 auto value_node = node->cast<ValueNodePtr>();
33 if (value_node == nullptr) {
34 return nullptr;
35 }
36 auto value = value_node->value();
37 if (value == nullptr || !(value->isa<tensor::Tensor>())) {
38 return nullptr;
39 }
40 auto tensor = value->cast<tensor::TensorPtr>();
41 if (tensor == nullptr || tensor->data_ptr() == nullptr || tensor->data_c() == nullptr) {
42 return nullptr;
43 }
44 return tensor;
45 }
46
NeedCompress(const tensor::TensorPtr & tensor)47 bool MiniaturizationPass::NeedCompress(const tensor::TensorPtr &tensor) {
48 auto tensor_data_ptr = tensor->data_ptr();
49 auto item_size = tensor_data_ptr->itemsize();
50 auto item_num = tensor_data_ptr->size();
51 auto data_ptr = tensor_data_ptr->data();
52 // No need cast to fill ops while tensor data size is small.
53 if (item_num < COMPRESS_TRIGGER_SIZE_) {
54 return false;
55 }
56 int ret = 0;
57 for (ssize_t idx = 1; idx < item_num; idx++) {
58 auto offset = idx * item_size;
59 // No memcmp_s provide in secure lib of huawei
60 ret = memcmp(static_cast<uint8_t *>(data_ptr) + offset, static_cast<uint8_t *>(data_ptr) + offset - item_size,
61 item_size);
62 if (ret != 0) {
63 break;
64 }
65 }
66 return ret == 0;
67 }
68
GetFirstVal(const tensor::TensorPtr & tensor)69 static inline ValuePtr GetFirstVal(const tensor::TensorPtr &tensor) {
70 auto tensor_data_ptr = tensor->data_ptr();
71 auto data_type = tensor->data_type();
72 auto data_ptr = tensor_data_ptr->data();
73 if (data_type == kNumberTypeFloat32) {
74 float val = static_cast<float *>(data_ptr)[0];
75 return MakeValue(val);
76 }
77 if (data_type == kNumberTypeUInt32) {
78 int32_t val = static_cast<int32_t *>(data_ptr)[0];
79 return MakeValue(val);
80 }
81 return nullptr;
82 }
83
Run(const FuncGraphPtr & func_graph)84 bool MiniaturizationPass::Run(const FuncGraphPtr &func_graph) {
85 auto node_list = TopoSort(func_graph->get_return());
86 auto manager = Manage(func_graph, true);
87 MS_ASSERT(manager != nullptr);
88 bool changed = false;
89 // this pass replace the tensor that has large data size and same value with fill ops
90 for (auto &node : node_list) {
91 auto cnode = node->cast<CNodePtr>();
92 if (cnode == nullptr) {
93 continue;
94 }
95 changed = ProcessOneCNode(func_graph, cnode);
96 }
97 return changed;
98 }
ProcessOneCNode(const FuncGraphPtr & func_graph,const CNodePtr & cnode)99 bool MiniaturizationPass::ProcessOneCNode(const FuncGraphPtr &func_graph, const CNodePtr &cnode) {
100 bool changed;
101 auto inputs = cnode->inputs();
102 for (size_t i = 1; i < inputs.size(); i++) {
103 auto tensor = GetTensorFromNode(inputs[i]);
104 if (tensor == nullptr) {
105 continue;
106 }
107 // No need cast to fill ops while tensor data size is small.
108 if (!NeedCompress(tensor)) {
109 continue;
110 }
111
112 ValuePtr input1 = GetFirstVal(tensor);
113 if (input1 == nullptr) {
114 MS_LOG(WARNING) << cnode->fullname_with_scope() << " input " << i << " converter to Fill ops failed.";
115 continue;
116 }
117
118 ops::Fill ops_fill;
119 auto input0 = ops_fill.GetPrim();
120 auto node_input0 = NewValueNode(input0);
121 auto node_input1 = NewValueNode(input1);
122 auto input2 = MakeValue(tensor->shape());
123 auto node_input2 = NewValueNode(input2);
124 AnfNodePtr fill_node =
125 std::make_shared<CNode>(std::vector<AnfNodePtr>{node_input0, node_input1, node_input2}, func_graph);
126 func_graph->manager()->Replace(cnode->input(i), fill_node);
127 changed = true;
128 }
129 return changed;
130 }
131 } // namespace mindspore::opt
132