• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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