1fdb40e516bfdad52cacf95901fcc76e3f4d53d5
[platform/core/ml/nnfw.git] / compiler / luci / export / src / CircleExporterUtils.cpp
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 "CircleExporterUtils.h"
18
19 #include <oops/InternalExn.h>
20
21 #include <cassert>
22 #include <memory>
23
24 namespace luci
25 {
26
27 circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func)
28 {
29   switch (func)
30   {
31     case luci::FusedActFunc::NONE:
32       return circle::ActivationFunctionType_NONE;
33     case luci::FusedActFunc::RELU:
34       return circle::ActivationFunctionType_RELU;
35     case luci::FusedActFunc::RELU_N1_TO_1:
36       return circle::ActivationFunctionType_RELU_N1_TO_1;
37     case luci::FusedActFunc::RELU6:
38       return circle::ActivationFunctionType_RELU6;
39     case luci::FusedActFunc::TANH:
40       return circle::ActivationFunctionType_TANH;
41     case luci::FusedActFunc::SIGN_BIT:
42       return circle::ActivationFunctionType_SIGN_BIT;
43     default:
44       INTERNAL_EXN_V("trying to convert unsupported luci::FusedActFunc", oops::to_uint32(func));
45   }
46 }
47
48 circle::TensorType to_circle_tensortype(loco::DataType type)
49 {
50   switch (type)
51   {
52     case loco::DataType::U8:
53       return circle::TensorType_UINT8;
54
55     case loco::DataType::S8:
56       return circle::TensorType_INT8;
57     case loco::DataType::S16:
58       return circle::TensorType_INT16;
59     case loco::DataType::S32:
60       return circle::TensorType_INT32;
61     case loco::DataType::S64:
62       return circle::TensorType_INT64;
63
64     case loco::DataType::FLOAT16:
65       return circle::TensorType_FLOAT16;
66     case loco::DataType::FLOAT32:
67       return circle::TensorType_FLOAT32;
68
69     case loco::DataType::BOOL:
70       return circle::TensorType_BOOL;
71
72     default:
73       INTERNAL_EXN_V("failed to convert unsupported loco::DataType", oops::to_uint32(type));
74   }
75 }
76
77 circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode)
78 {
79   switch (mode)
80   {
81     case luci::MirrorPadMode::REFLECT:
82       return circle::MirrorPadMode::MirrorPadMode_REFLECT;
83     case luci::MirrorPadMode::SYMMETRIC:
84       return circle::MirrorPadMode::MirrorPadMode_SYMMETRIC;
85     default:
86       INTERNAL_EXN_V("trying to convert unsupported luci::MirrorPadMode", oops::to_uint32(mode));
87   }
88 }
89
90 circle::DimensionType to_circle_dimensiontype(luci::DimensionType type)
91 {
92   switch (type)
93   {
94     case luci::DimensionType::DENSE:
95       return circle::DimensionType_DENSE;
96     case luci::DimensionType::SPARSE_CSR:
97       return circle::DimensionType_SPARSE_CSR;
98     default:
99       INTERNAL_EXN_V("trying to convert unsupported luci::DimensionType", oops::to_uint32(type));
100   }
101 }
102
103 flatbuffers::Offset<void> to_circle_sparse_index_vector(flatbuffers::FlatBufferBuilder &fb,
104                                                         const SparseIndexVector &sparse_idx_vec)
105 {
106   auto type = sparse_idx_vec.type();
107   switch (type)
108   {
109     case luci::SparseIndexVectorType::NONE:
110       return flatbuffers::Offset<void>();
111     case luci::SparseIndexVectorType::I32:
112     {
113       return circle::CreateInt32VectorDirect(fb, sparse_idx_vec.as_int32_vector()).Union();
114     }
115     case luci::SparseIndexVectorType::U16:
116     {
117       return circle::CreateUint16VectorDirect(fb, sparse_idx_vec.as_uint16_vector()).Union();
118     }
119     case luci::SparseIndexVectorType::U8:
120     {
121       return circle::CreateUint8VectorDirect(fb, sparse_idx_vec.as_uint8_vector()).Union();
122     }
123     default:
124       INTERNAL_EXN_V("trying to convert unsupported luci::SparseIndexVectorType",
125                      oops::to_uint32(type));
126   }
127 }
128
129 circle::SparseIndexVector to_circle_sparse_index_vector_type(luci::SparseIndexVectorType type)
130 {
131   switch (type)
132   {
133     case luci::SparseIndexVectorType::NONE:
134       return circle::SparseIndexVector_NONE;
135     case luci::SparseIndexVectorType::I32:
136       return circle::SparseIndexVector_Int32Vector;
137     case luci::SparseIndexVectorType::U16:
138       return circle::SparseIndexVector_Uint16Vector;
139     case luci::SparseIndexVectorType::U8:
140       return circle::SparseIndexVector_Uint8Vector;
141     default:
142       INTERNAL_EXN_V("trying to convert unsupported luci::SparseIndexVectorType",
143                      oops::to_uint32(type));
144   }
145 }
146
147 } // namespace luci
148
149 namespace luci
150 {
151
152 uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code,
153                                                     const int32_t op_version)
154 {
155   assert(op_version > 0);
156
157   auto it = _operator_codes.find(OpCode{builtin_code, "", op_version});
158   if (it != _operator_codes.end())
159   {
160     return it->second;
161   }
162   auto idx = static_cast<uint32_t>(_operator_codes.size());
163   _operator_codes.emplace(OpCode{builtin_code, "", op_version}, idx);
164   return idx;
165 }
166
167 uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_code)
168 {
169   const circle::BuiltinOperator builtin_code = circle::BuiltinOperator_CUSTOM;
170   auto it = _operator_codes.find(OpCode{builtin_code, custom_code});
171   if (it != _operator_codes.end())
172   {
173     return it->second;
174   }
175   auto idx = static_cast<uint32_t>(_operator_codes.size());
176   _operator_codes.emplace(OpCode{builtin_code, custom_code}, idx);
177   return idx;
178 }
179
180 circle::Padding getOpPadding(const loco::Padding2D *pad, const loco::Stride<2> *stride,
181                              const ShapeDescription &ifm, const ShapeDescription &ofm)
182 {
183   // VALID padding
184   if (pad->top() == 0 && pad->bottom() == 0 && pad->left() == 0 && pad->right() == 0)
185     return circle::Padding_VALID;
186
187   // SAME padding
188   //
189   // For same padding, by definition, following equation should hold:
190   //   O = floor((I - 1) / S) + 1
191   //   where input size I, output size O, stride S
192   //
193   // NOTE input and output 'feature' map are shape of NHWC
194   bool same_padding_criterion_1 =
195       (static_cast<uint32_t>(ofm._dims[1]) == (ifm._dims[1] - 1) / stride->vertical() + 1) &&
196       (static_cast<uint32_t>(ofm._dims[2]) == (ifm._dims[2] - 1) / stride->horizontal() + 1);
197
198   // For same padding, rear padding is same or bigger than front padding by at most 1
199   bool same_padding_criterion_2 =
200       (pad->top() <= pad->bottom()) && (pad->bottom() <= pad->top() + 1) &&
201       (pad->left() <= pad->right()) && (pad->right() <= pad->left() + 1);
202
203   if (same_padding_criterion_1 && same_padding_criterion_2)
204     return circle::Padding_SAME;
205
206   INTERNAL_EXN("Unsupported padding criteria");
207 }
208
209 circle::Padding getOpPadding(const luci::Padding pad)
210 {
211   if (pad == luci::Padding::VALID)
212     return circle::Padding_VALID;
213   if (pad == luci::Padding::SAME)
214     return circle::Padding_SAME;
215
216   INTERNAL_EXN_V("Unsupported luci::Padding", oops::to_uint32(pad));
217 }
218
219 namespace
220 {
221
222 class CircleTensorIndexAnnotation final : public loco::NodeAnnotation
223 {
224 public:
225   CircleTensorIndexAnnotation(const CircleTensorIndex &index) : _index{index}
226   {
227     // DO NOTHING
228   }
229
230 public:
231   const CircleTensorIndex &index(void) const { return _index; }
232
233 private:
234   CircleTensorIndex _index;
235 };
236
237 } // namespace
238
239 void set_tensor_index(loco::Node *node, const CircleTensorIndex &tensor_id)
240 {
241   assert(node->annot<CircleTensorIndexAnnotation>() == nullptr);
242   node->annot(std::make_unique<CircleTensorIndexAnnotation>(tensor_id));
243 }
244
245 CircleTensorIndex get_tensor_index(loco::Node *node)
246 {
247   assert(node->annot<CircleTensorIndexAnnotation>() != nullptr);
248   return node->annot<CircleTensorIndexAnnotation>()->index();
249 }
250
251 } // namespace luci