ONE - On-device Neural Engine
Loading...
Searching...
No Matches
CircleExporterUtils.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 "CircleExporterUtils.h"
19
20#include <oops/InternalExn.h>
21
22#include <cassert>
23#include <memory>
24
25namespace luci
26{
27
28circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func)
29{
30 switch (func)
31 {
33 return circle::ActivationFunctionType_NONE;
35 return circle::ActivationFunctionType_RELU;
37 return circle::ActivationFunctionType_RELU_N1_TO_1;
39 return circle::ActivationFunctionType_RELU6;
41 return circle::ActivationFunctionType_TANH;
43 return circle::ActivationFunctionType_SIGN_BIT;
44 default:
45 INTERNAL_EXN_V("trying to convert unsupported luci::FusedActFunc", oops::to_uint32(func));
46 }
47}
48
49circle::TensorType to_circle_tensortype(loco::DataType type)
50{
51 switch (type)
52 {
53 case loco::DataType::U4:
54 return circle::TensorType_UINT4;
55 case loco::DataType::U8:
56 return circle::TensorType_UINT8;
57
58 case loco::DataType::S4:
59 return circle::TensorType_INT4;
60 case loco::DataType::S8:
61 return circle::TensorType_INT8;
62 case loco::DataType::S16:
63 return circle::TensorType_INT16;
64 case loco::DataType::S32:
65 return circle::TensorType_INT32;
66 case loco::DataType::S64:
67 return circle::TensorType_INT64;
68
69 case loco::DataType::FLOAT16:
70 return circle::TensorType_FLOAT16;
71 case loco::DataType::FLOAT32:
72 return circle::TensorType_FLOAT32;
73
74 case loco::DataType::BOOL:
75 return circle::TensorType_BOOL;
76
77 case loco::DataType::STRING:
78 return circle::TensorType_STRING;
79
80 case loco::DataType::MXFP4:
81 return circle::TensorType_MXFP4;
82 case loco::DataType::MXINT8:
83 return circle::TensorType_MXINT8;
84
85 default:
86 INTERNAL_EXN_V("failed to convert unsupported loco::DataType", oops::to_uint32(type));
87 }
88}
89
91{
92 switch (mode)
93 {
95 return circle::MirrorPadMode::MirrorPadMode_REFLECT;
97 return circle::MirrorPadMode::MirrorPadMode_SYMMETRIC;
98 default:
99 INTERNAL_EXN_V("trying to convert unsupported luci::MirrorPadMode", oops::to_uint32(mode));
100 }
101}
102
103circle::RoPEMode to_circle_rope(luci::RoPEMode mode)
104{
105 switch (mode)
106 {
108 return circle::RoPEMode::RoPEMode_GPT_NEOX;
110 return circle::RoPEMode::RoPEMode_GPT_J;
111 default:
112 INTERNAL_EXN_V("trying to convert unsupported luci::RoPEMode", oops::to_uint32(mode));
113 }
114}
115
116circle::FullyConnectedOptionsWeightsFormat
118{
119 switch (format)
120 {
122 return circle::FullyConnectedOptionsWeightsFormat_DEFAULT;
124 return circle::FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8;
126 return circle::FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32;
127 default:
128 INTERNAL_EXN_V("trying to convert unsupported luci::WeightsFormat", oops::to_uint32(format));
129 }
130}
131
133{
134 switch (type)
135 {
137 return circle::DimensionType_DENSE;
139 return circle::DimensionType_SPARSE_CSR;
140 default:
141 INTERNAL_EXN_V("trying to convert unsupported luci::DimensionType", oops::to_uint32(type));
142 }
143}
144
146 const SparseIndexVector &sparse_idx_vec)
147{
148 auto type = sparse_idx_vec.type();
149 switch (type)
150 {
154 {
155 return circle::CreateInt32VectorDirect(fb, sparse_idx_vec.as_int32_vector()).Union();
156 }
158 {
159 return circle::CreateUint16VectorDirect(fb, sparse_idx_vec.as_uint16_vector()).Union();
160 }
162 {
163 return circle::CreateUint8VectorDirect(fb, sparse_idx_vec.as_uint8_vector()).Union();
164 }
165 default:
166 INTERNAL_EXN_V("trying to convert unsupported luci::SparseIndexVectorType",
167 oops::to_uint32(type));
168 }
169}
170
172{
173 switch (type)
174 {
176 return circle::SparseIndexVector_NONE;
178 return circle::SparseIndexVector_Int32Vector;
180 return circle::SparseIndexVector_Uint16Vector;
182 return circle::SparseIndexVector_Uint8Vector;
183 default:
184 INTERNAL_EXN_V("trying to convert unsupported luci::SparseIndexVectorType",
185 oops::to_uint32(type));
186 }
187}
188
189circle::BuiltinOperator circle_builtin_operator(const luci::CircleNode *node)
190{
192}
193
194circle::BuiltinOptions circle_builtin_options(const luci::CircleNode *node)
195{
196 if (auto cast = dynamic_cast<const luci::CircleCast *>(node))
197 {
198 return (cast->out_data_type() == loco::DataType::Unknown) ? circle::BuiltinOptions_NONE
199 : circle::BuiltinOptions_CastOptions;
200 }
201
202 return node->accept(&BuiltinOptionsMappingRule::get());
203}
204
205std::string circle_custom_code(const luci::CircleNode *node)
206{
207 if (auto custom_node = dynamic_cast<const luci::CircleCustom *>(node))
208 {
209 return custom_node->custom_code();
210 }
211
212 return "";
213}
214
217{
218 if (auto custom_node = dynamic_cast<const luci::CircleCustom *>(node))
219 {
220 std::vector<uint8_t> custom_options_vec{custom_node->custom_options().begin(),
221 custom_node->custom_options().end()};
222 return fb.CreateVector(custom_options_vec);
223 }
224
225 return 0;
226}
227
228} // namespace luci
229
230namespace luci
231{
232
233uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code,
234 const std::string &custom_code,
235 const int32_t op_version)
236{
237 assert(op_version > 0);
238
239 auto it = _operator_codes.find(OpCode{builtin_code, custom_code, op_version});
240 if (it != _operator_codes.end())
241 {
242 return it->second;
243 }
244 auto idx = static_cast<uint32_t>(_operator_codes.size());
245 _operator_codes.emplace(OpCode{builtin_code, custom_code, op_version}, idx);
246 return idx;
247}
248
249circle::Padding getOpPadding(const loco::Padding2D *pad, const loco::Stride<2> *stride,
250 const ShapeDescription &ifm, const ShapeDescription &ofm)
251{
252 // VALID padding
253 if (pad->top() == 0 && pad->bottom() == 0 && pad->left() == 0 && pad->right() == 0)
254 return circle::Padding_VALID;
255
256 // SAME padding
257 //
258 // For same padding, by definition, following equation should hold:
259 // O = floor((I - 1) / S) + 1
260 // where input size I, output size O, stride S
261 //
262 // NOTE input and output 'feature' map are shape of NHWC
263 bool same_padding_criterion_1 =
264 (static_cast<uint32_t>(ofm._dims[1]) == (ifm._dims[1] - 1) / stride->vertical() + 1) &&
265 (static_cast<uint32_t>(ofm._dims[2]) == (ifm._dims[2] - 1) / stride->horizontal() + 1);
266
267 // For same padding, rear padding is same or bigger than front padding by at most 1
268 bool same_padding_criterion_2 =
269 (pad->top() <= pad->bottom()) && (pad->bottom() <= pad->top() + 1) &&
270 (pad->left() <= pad->right()) && (pad->right() <= pad->left() + 1);
271
272 if (same_padding_criterion_1 && same_padding_criterion_2)
273 return circle::Padding_SAME;
274
275 INTERNAL_EXN("Unsupported padding criteria");
276}
277
278circle::Padding getOpPadding(const luci::Padding pad)
279{
280 if (pad == luci::Padding::VALID)
281 return circle::Padding_VALID;
282 if (pad == luci::Padding::SAME)
283 return circle::Padding_SAME;
284
285 INTERNAL_EXN_V("Unsupported luci::Padding", oops::to_uint32(pad));
286}
287
288namespace
289{
290
291class CircleTensorIndexAnnotation final : public loco::NodeAnnotation
292{
293public:
294 CircleTensorIndexAnnotation(const CircleTensorIndex &index) : _index{index}
295 {
296 // DO NOTHING
297 }
298
299public:
300 const CircleTensorIndex &index(void) const { return _index; }
301
302private:
303 CircleTensorIndex _index;
304};
305
306} // namespace
307
308void set_tensor_index(loco::Node *node, const CircleTensorIndex &tensor_id)
309{
310 assert(node->annot<CircleTensorIndexAnnotation>() == nullptr);
311 node->annot(std::make_unique<CircleTensorIndexAnnotation>(tensor_id));
312}
313
315{
316 if (node->annot<CircleTensorIndexAnnotation>() != nullptr)
317 node->annot<CircleTensorIndexAnnotation>(nullptr);
318}
319
321{
322 assert(node->annot<CircleTensorIndexAnnotation>() != nullptr);
323 return node->annot<CircleTensorIndexAnnotation>()->index();
324}
325
326} // namespace luci
#define INTERNAL_EXN(msg)
@ brief throw internal exception with message
Definition InternalExn.h:25
#define INTERNAL_EXN_V(msg, val)
@ brief throw internal exception with message and value
Definition InternalExn.h:28
Helper class to hold data needed in creation of a FlatBuffer. To serialize data, you typically call o...
Offset< Vector< T > > CreateVector(const T *v, size_t len)
Serialize an array into a FlatBuffer vector.
const T * annot(void) const
Retrieve a stored annotation of type T.
Logical unit of computation.
Definition Node.h:54
uint32_t left(void) const
Definition Padding2D.h:49
uint32_t top(void) const
Definition Padding2D.h:41
uint32_t bottom(void) const
Definition Padding2D.h:45
uint32_t right(void) const
Definition Padding2D.h:53
Stride configuration for N-dimensional spatial operations.
Definition Stride.h:28
static BuiltinOperatorMappingRule & get()
static BuiltinOptionsMappingRule & get()
CAST in Circle.
Definition CircleCast.h:32
CUSTOM in Circle.
const std::vector< uint8_t > * as_uint8_vector(void) const
SparseIndexVectorType type(void) const
const std::vector< uint16_t > * as_uint16_vector(void) const
const std::vector< int32_t > * as_int32_vector(void) const
DataType
"scalar" value type
Definition DataType.h:27
flatbuffers::Offset< void > to_circle_sparse_index_vector(flatbuffers::FlatBufferBuilder &fb, const SparseIndexVector &sparse_idx_vec)
circle::BuiltinOptions circle_builtin_options(const luci::CircleNode *node)
void set_tensor_index(loco::Node *node, const CircleTensorIndex &tensor_id)
flatbuffers::Offset< flatbuffers::Vector< uint8_t > > circle_custom_options(flatbuffers::FlatBufferBuilder &fb, const luci::CircleNode *node)
circle::Padding getOpPadding(const loco::Padding2D *pad, const loco::Stride< 2 > *stride, const ShapeDescription &ifm, const ShapeDescription &ofm)
circle::DimensionType to_circle_dimensiontype(luci::DimensionType type)
circle::FullyConnectedOptionsWeightsFormat to_circle_weightsformat(luci::CircleFullyConnected::WeightsFormat format)
circle::SparseIndexVector to_circle_sparse_index_vector_type(luci::SparseIndexVectorType type)
circle::RoPEMode to_circle_rope(luci::RoPEMode mode)
circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func)
@ SPARSE_CSR
int32_t CircleTensorIndex
circle::TensorType to_circle_tensortype(loco::DataType type)
SparseIndexVectorType
void clear_tensor_index(loco::Node *node)
CircleTensorIndex get_tensor_index(loco::Node *node)
circle::BuiltinOperator circle_builtin_operator(const luci::CircleNode *node)
circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode)
std::string circle_custom_code(const luci::CircleNode *node)
loco::GraphInputIndex index(const TFPlaceholder *node)
Definition TFNode.cpp:54
uint32_t to_uint32(T a)
Definition InternalExn.h:33
Extensible Node Metadata.
Definition Node.h:39
T accept(CircleNodeVisitorBase< T > *) const
std::unordered_map< OpCode, uint32_t > _operator_codes
uint32_t registerBuiltinOpcode(circle::BuiltinOperator builtin_code, const std::string &custom_code, const int32_t op_version)
if opcode is not registered in table of opcodes add it
std::vector< int32_t > _dims