Imported Upstream version 1.7.0
[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     default:
40       INTERNAL_EXN_V("trying to convert unsupported luci::FusedActFunc", oops::to_uint32(func));
41   }
42 }
43
44 circle::TensorType to_circle_tensortype(loco::DataType type)
45 {
46   switch (type)
47   {
48     case loco::DataType::U8:
49       return circle::TensorType_UINT8;
50
51     case loco::DataType::S8:
52       return circle::TensorType_INT8;
53     case loco::DataType::S16:
54       return circle::TensorType_INT16;
55     case loco::DataType::S32:
56       return circle::TensorType_INT32;
57     case loco::DataType::S64:
58       return circle::TensorType_INT64;
59
60     case loco::DataType::FLOAT16:
61       return circle::TensorType_FLOAT16;
62     case loco::DataType::FLOAT32:
63       return circle::TensorType_FLOAT32;
64
65     case loco::DataType::BOOL:
66       return circle::TensorType_BOOL;
67
68     default:
69       INTERNAL_EXN_V("failed to convert unsupported loco::DataType", oops::to_uint32(type));
70   }
71 }
72
73 circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode)
74 {
75   switch (mode)
76   {
77     case luci::MirrorPadMode::REFLECT:
78       return circle::MirrorPadMode::MirrorPadMode_REFLECT;
79     case luci::MirrorPadMode::SYMMETRIC:
80       return circle::MirrorPadMode::MirrorPadMode_SYMMETRIC;
81     default:
82       INTERNAL_EXN_V("trying to convert unsupported luci::MirrorPadMode", oops::to_uint32(mode));
83   }
84 }
85
86 } // namespace luci
87
88 namespace luci
89 {
90
91 uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code,
92                                                     const int32_t op_version)
93 {
94   assert(op_version > 0);
95
96   auto it = _operator_codes.find(OpCode{builtin_code, "", op_version});
97   if (it != _operator_codes.end())
98   {
99     return it->second;
100   }
101   auto idx = static_cast<uint32_t>(_operator_codes.size());
102   _operator_codes.emplace(OpCode{builtin_code, "", op_version}, idx);
103   return idx;
104 }
105
106 uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_code)
107 {
108   const circle::BuiltinOperator builtin_code = circle::BuiltinOperator_CUSTOM;
109   auto it = _operator_codes.find(OpCode{builtin_code, custom_code});
110   if (it != _operator_codes.end())
111   {
112     return it->second;
113   }
114   auto idx = static_cast<uint32_t>(_operator_codes.size());
115   _operator_codes.emplace(OpCode{builtin_code, custom_code}, idx);
116   return idx;
117 }
118
119 circle::Padding getOpPadding(const loco::Padding2D *pad, const loco::Stride<2> *stride,
120                              const ShapeDescription &ifm, const ShapeDescription &ofm)
121 {
122   // VALID padding
123   if (pad->top() == 0 && pad->bottom() == 0 && pad->left() == 0 && pad->right() == 0)
124     return circle::Padding_VALID;
125
126   // SAME padding
127   //
128   // For same padding, by definition, following equation should hold:
129   //   O = floor((I - 1) / S) + 1
130   //   where input size I, output size O, stride S
131   //
132   // NOTE input and output 'feature' map are shape of NHWC
133   bool same_padding_criterion_1 =
134       (static_cast<uint32_t>(ofm._dims[1]) == (ifm._dims[1] - 1) / stride->vertical() + 1) &&
135       (static_cast<uint32_t>(ofm._dims[2]) == (ifm._dims[2] - 1) / stride->horizontal() + 1);
136
137   // For same padding, rear padding is same or bigger than front padding by at most 1
138   bool same_padding_criterion_2 =
139       (pad->top() <= pad->bottom()) && (pad->bottom() <= pad->top() + 1) &&
140       (pad->left() <= pad->right()) && (pad->right() <= pad->left() + 1);
141
142   if (same_padding_criterion_1 && same_padding_criterion_2)
143     return circle::Padding_SAME;
144
145   INTERNAL_EXN("Unsupported padding criteria");
146 }
147
148 circle::Padding getOpPadding(const luci::Padding pad)
149 {
150   if (pad == luci::Padding::VALID)
151     return circle::Padding_VALID;
152   if (pad == luci::Padding::SAME)
153     return circle::Padding_SAME;
154
155   INTERNAL_EXN_V("Unsupported luci::Padding", oops::to_uint32(pad));
156 }
157
158 namespace
159 {
160
161 class CircleTensorIndexAnnotation final : public loco::NodeAnnotation
162 {
163 public:
164   CircleTensorIndexAnnotation(const CircleTensorIndex &index) : _index{index}
165   {
166     // DO NOTHING
167   }
168
169 public:
170   const CircleTensorIndex &index(void) const { return _index; }
171
172 private:
173   CircleTensorIndex _index;
174 };
175
176 } // namespace
177
178 void set_tensor_index(loco::Node *node, const CircleTensorIndex &tensor_id)
179 {
180   assert(node->annot<CircleTensorIndexAnnotation>() == nullptr);
181   node->annot(std::make_unique<CircleTensorIndexAnnotation>(tensor_id));
182 }
183
184 CircleTensorIndex get_tensor_index(loco::Node *node)
185 {
186   assert(node->annot<CircleTensorIndexAnnotation>() != nullptr);
187   return node->annot<CircleTensorIndexAnnotation>()->index();
188 }
189
190 } // namespace luci