ONE - On-device Neural Engine
Loading...
Searching...
No Matches
GraphLoader.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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 "loader/GraphLoader.h"
18
19namespace luci_interpreter
20{
21namespace
22{
23
24bool isInplaceOperation(const circle::BuiltinOperator &op)
25{
26 switch (op)
27 {
28 case circle::BuiltinOperator_ABS:
29 case circle::BuiltinOperator_CEIL:
30 case circle::BuiltinOperator_LOGISTIC:
31 case circle::BuiltinOperator_RESHAPE:
32 case circle::BuiltinOperator_ELU:
33 case circle::BuiltinOperator_EXPAND_DIMS:
34 case circle::BuiltinOperator_EXP:
35 case circle::BuiltinOperator_TANH:
36 case circle::BuiltinOperator_LEAKY_RELU:
37 case circle::BuiltinOperator_LOG:
38 case circle::BuiltinOperator_RELU:
39 case circle::BuiltinOperator_RELU6:
40 case circle::BuiltinOperator_ROUND:
41 case circle::BuiltinOperator_ADD:
42 case circle::BuiltinOperator_MUL:
43 case circle::BuiltinOperator_SUB:
44 case circle::BuiltinOperator_WHILE:
45 case circle::BuiltinOperator_ZEROS_LIKE:
46 return true;
47 default:
48 return false;
49 }
50}
51
52bool isSingleUsageOfTensor(CircleReader *reader, const int32_t tensor_index)
53{
54 uint32_t usage_count = 0;
55
56 const auto operators = reader->operators();
57 for (uint32_t i = 0; i < operators.size(); ++i)
58 {
59 const auto *op = operators.at(i);
60 assert(op != nullptr);
61
62 const auto *op_inputs = op->inputs();
63 for (int32_t j = 0; j < op_inputs->size(); ++j)
64 {
65 const auto input_index = op_inputs->operator[](j);
66 if (input_index == tensor_index)
67 {
68 if (++usage_count > 1)
69 return false;
70 }
71 }
72 }
73
74 // Let's check that it is not graph output
75 if (usage_count == 1)
76 {
77 const auto &outputs_indexes = reader->outputs();
78 bool is_graph_output = (std::find(outputs_indexes.begin(), outputs_indexes.end(),
79 tensor_index) != outputs_indexes.end());
80 if (is_graph_output)
81 return false;
82 }
83
84 return true;
85}
86
87} // namespace
88
90{
91 const auto operators = reader->operators();
92 const auto graph_outputs = reader->outputs();
93 for (uint32_t i = 0; i < operators.size(); ++i)
94 {
95 const auto *op = operators.at(i);
96 assert(op != nullptr);
97
98 // Check inplace optimization for operation with single input and single output
99 if (isInplaceOperation(reader->builtin_code(op)))
100 {
101 const auto *op_inputs = op->inputs();
102 const auto *op_outputs = op->outputs();
103
104 bool is_inplace = true;
105 auto non_const_input_it = op_inputs->begin();
106 while (true)
107 {
108 non_const_input_it =
109 std::find_if(non_const_input_it, op_inputs->end(), [&reader](const auto input_idx) {
110 if (input_idx == -1)
111 return false;
112
113 return not Tensor::is_constant_tensor(reader, reader->tensors()[input_idx]);
114 });
115
116 if (non_const_input_it == op_inputs->end())
117 break;
118
119 auto dist = std::distance(op_inputs->begin(), non_const_input_it);
120
121 const auto non_const_input_idx = *non_const_input_it;
122
123 // Check single usage of input tensor
124 if (not isSingleUsageOfTensor(reader, non_const_input_idx))
125 {
126 is_inplace = false;
127 break;
128 }
129
130 // Let's check single usage of output tensor
131 if (dist >= op_outputs->size() and op_outputs->size() == 1)
132 dist = 0;
133 assert(dist < op_outputs->size());
134 const auto output_index = op_outputs->operator[](dist);
135 if (not isSingleUsageOfTensor(reader, output_index))
136 {
137 is_inplace = false;
138 break;
139 }
140
141 // Check that num elements are equal
142 {
143 const auto *input_non_const_tensor = reader->tensors().at(non_const_input_idx);
144 const auto *output_tensor = reader->tensors().at(output_index);
145 if (Tensor::num_elements(input_non_const_tensor) != Tensor::num_elements(output_tensor))
146 {
147 is_inplace = false;
148 break;
149 }
150 }
151
152 // Let's check that output is not a graph output tensor
153 // TODO: check this statement
154 {
155 if (std::find(graph_outputs.begin(), graph_outputs.end(), output_index) !=
156 graph_outputs.end())
157 {
158 is_inplace = false;
159 break;
160 }
161 }
162
163 non_const_input_it++;
164 }
165
166 if (is_inplace)
167 runtime_graph->addInplaceOpIndex(op);
168 }
169 }
170}
171
172} // namespace luci_interpreter
Loads Circle file and provides helpers to access attributes.
CircleOperators operators() const
CircleTensors tensors() const
VectorWrapper< int32_t > outputs() const
circle::BuiltinOperator builtin_code(const circle::Operator *op) const
value_type at(uint32_t i) const
static void checkInplaceOps(CircleReader *reader, RuntimeGraph *runtime_graph)
void addInplaceOpIndex(const circle::Operator *op)
int32_t size[5]
Definition Slice.cpp:35