Imported Upstream version 1.18.0
[platform/core/ml/nnfw.git] / compiler / luci / import / src / CircleReader.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 "luci/Import/CircleReader.h"
18
19 #include <memory>
20 #include <sstream>
21 #include <string>
22
23 namespace luci
24 {
25
26 bool is_valid(const circle::OperatorCodeT &opcode)
27 {
28   circle::BuiltinOperator code = opcode.builtin_code;
29   return (circle::BuiltinOperator_MIN <= code && code <= circle::BuiltinOperator_MAX);
30 }
31
32 bool is_custom(const circle::OperatorCodeT &opcode)
33 {
34   circle::BuiltinOperator code = opcode.builtin_code;
35   return (code == circle::BuiltinOperator_CUSTOM);
36 }
37
38 std::string opcode_name(const circle::OperatorCodeT &opcode)
39 {
40   if (!is_valid(opcode))
41   {
42     std::ostringstream oss;
43     oss << "(invalid)";
44     return oss.str();
45   }
46
47   if (is_custom(opcode))
48   {
49     if (opcode.custom_code.empty())
50       return "(invalid custom)";
51
52     return opcode.custom_code;
53   }
54
55   circle::BuiltinOperator code = opcode.builtin_code;
56   return circle::EnumNameBuiltinOperator(code);
57 }
58
59 const char *tensor_name(const circle::TensorT &tensor)
60 {
61   static const char *kEmptyTensorName = "(noname)";
62
63   if (!tensor.name.empty())
64     return tensor.name.c_str();
65
66   return kEmptyTensorName;
67 }
68
69 const circle::QuantizationParametersT *tensor_quantization(const circle::TensorT &tensor)
70 {
71   return tensor.quantization.get();
72 }
73
74 loco::DataType luci_datatype(const circle::TensorType type)
75 {
76   switch (type)
77   {
78     case circle::TensorType_FLOAT32:
79       return loco::DataType::FLOAT32;
80     case circle::TensorType_FLOAT16:
81       return loco::DataType::FLOAT16;
82     case circle::TensorType_INT32:
83       return loco::DataType::S32;
84     case circle::TensorType_UINT8:
85       return loco::DataType::U8;
86     case circle::TensorType_INT64:
87       return loco::DataType::S64;
88     case circle::TensorType_STRING:
89       return loco::DataType::STRING;
90     case circle::TensorType_BOOL:
91       return loco::DataType::BOOL;
92     case circle::TensorType_INT16:
93       return loco::DataType::S16;
94     case circle::TensorType_COMPLEX64:
95       break;
96     case circle::TensorType_INT8:
97       return loco::DataType::S8;
98     default:
99       break;
100   }
101   assert(false);
102   return loco::DataType::Unknown;
103 }
104
105 FusedActFunc luci_actfunc(const circle::ActivationFunctionType type)
106 {
107   switch (type)
108   {
109     case circle::ActivationFunctionType::ActivationFunctionType_NONE:
110       return luci::FusedActFunc::NONE;
111     case circle::ActivationFunctionType::ActivationFunctionType_RELU:
112       return luci::FusedActFunc::RELU;
113     case circle::ActivationFunctionType::ActivationFunctionType_RELU_N1_TO_1:
114       return luci::FusedActFunc::RELU_N1_TO_1;
115     case circle::ActivationFunctionType::ActivationFunctionType_RELU6:
116       return luci::FusedActFunc::RELU6;
117     case circle::ActivationFunctionType::ActivationFunctionType_TANH:
118       return luci::FusedActFunc::TANH;
119     case circle::ActivationFunctionType::ActivationFunctionType_SIGN_BIT:
120       return luci::FusedActFunc::SIGN_BIT;
121     default:
122       break;
123   }
124   assert(false);
125   return luci::FusedActFunc::UNDEFINED;
126 }
127
128 Padding luci_padding(const circle::Padding padding)
129 {
130   switch (padding)
131   {
132     case circle::Padding::Padding_SAME:
133       return Padding::SAME;
134     case circle::Padding::Padding_VALID:
135       return Padding::VALID;
136   }
137   assert(false);
138   return Padding::UNDEFINED;
139 }
140
141 MirrorPadMode luci_mirrorpad_mode(const circle::MirrorPadMode mode)
142 {
143   switch (mode)
144   {
145     case circle::MirrorPadMode::MirrorPadMode_REFLECT:
146       return MirrorPadMode::REFLECT;
147     case circle::MirrorPadMode::MirrorPadMode_SYMMETRIC:
148       return MirrorPadMode::SYMMETRIC;
149   }
150   assert(false);
151   return MirrorPadMode::UNDEFINED;
152 }
153
154 luci::CircleFullyConnected::WeightsFormat
155 luci_weights_format(const circle::FullyConnectedOptionsWeightsFormat weights_format)
156 {
157   switch (weights_format)
158   {
159     case circle::FullyConnectedOptionsWeightsFormat_DEFAULT:
160       return luci::CircleFullyConnected::WeightsFormat::DEFAULT;
161     case circle::FullyConnectedOptionsWeightsFormat_SHUFFLED4x16INT8:
162       return luci::CircleFullyConnected::WeightsFormat::SHUFFLED4x16INT8;
163     case circle::FullyConnectedOptionsWeightsFormat_SHUFFLED16x1FLOAT32:
164       return luci::CircleFullyConnected::WeightsFormat::SHUFFLED16x1FLOAT32;
165     default:
166       throw std::runtime_error("Invalid FullyConnectedOptionsWeightsFormat");
167   }
168 }
169
170 DimensionType luci_dim_type(const circle::DimensionType dim_type)
171 {
172   switch (dim_type)
173   {
174     case circle::DimensionType_DENSE:
175       return DimensionType::DENSE;
176     case circle::DimensionType_SPARSE_CSR:
177       return DimensionType::SPARSE_CSR;
178     default:
179       throw std::runtime_error("Invalid DimensionType");
180   }
181 }
182
183 SparseIndexVector
184 luci_sparse_index_vector(const circle::SparseIndexVectorUnion &sparse_index_vector)
185 {
186   switch (sparse_index_vector.type)
187   {
188     case circle::SparseIndexVector_NONE:
189       return SparseIndexVector{SparseIndexVectorType::NONE, nullptr};
190     case circle::SparseIndexVector_Int32Vector:
191     {
192       const auto const_vec_ptr =
193         static_cast<const void *>(&(sparse_index_vector.AsInt32Vector()->values));
194       return SparseIndexVector{SparseIndexVectorType::I32, const_vec_ptr};
195     }
196     case circle::SparseIndexVector_Uint16Vector:
197     {
198       const auto const_vec_ptr =
199         static_cast<const void *>(&(sparse_index_vector.AsUint16Vector()->values));
200       return SparseIndexVector{SparseIndexVectorType::U16, const_vec_ptr};
201     }
202     case circle::SparseIndexVector_Uint8Vector:
203     {
204       const auto const_vec_ptr =
205         static_cast<const void *>(&(sparse_index_vector.AsUint8Vector()->values));
206       return SparseIndexVector{SparseIndexVectorType::U8, const_vec_ptr};
207     }
208     default:
209       throw std::runtime_error("Invalid SparseIndexVector type");
210   }
211 }
212
213 std::unique_ptr<CircleQuantParam>
214 luci_quantparam(const circle::QuantizationParametersT *quantization)
215 {
216   const auto &min = quantization->min;
217   const auto &max = quantization->max;
218   const auto &scale = quantization->scale;
219   const auto &zero_point = quantization->zero_point;
220   const auto &quantized_dimension = quantization->quantized_dimension;
221
222   if ((!min.empty() && !max.empty()) || (!scale.empty() && !zero_point.empty()))
223   {
224     auto quantparam = std::make_unique<CircleQuantParam>();
225
226     quantparam->min = min;
227     quantparam->max = max;
228     quantparam->scale = scale;
229     quantparam->zerop = zero_point;
230     quantparam->quantized_dimension = quantized_dimension;
231
232     return quantparam;
233   }
234
235   return nullptr;
236 }
237
238 std::unique_ptr<SparsityParam> luci_sparsityparam(const circle::SparsityParametersT *sparsity)
239 {
240   assert(sparsity);
241   const auto &traversal_order = sparsity->traversal_order;
242   const auto &block_map = sparsity->block_map;
243   const auto &dim_metadata = sparsity->dim_metadata;
244
245   // TODO find a condition that should return nullptr
246   auto sparsityparam = std::make_unique<SparsityParam>();
247
248   sparsityparam->traversal_order = traversal_order;
249   sparsityparam->block_map = block_map;
250   for (const auto &dm : dim_metadata)
251   {
252     sparsityparam->dim_metadata.emplace_back(luci_dim_type(dm->format), dm->dense_size,
253                                              luci_sparse_index_vector(dm->array_segments),
254                                              luci_sparse_index_vector(dm->array_indices));
255   }
256
257   return sparsityparam;
258 }
259
260 void copy_tensor_attributes(const circle::TensorT &tensor, CircleNode *node)
261 {
262   node->name(tensor_name(tensor));
263   node->dtype(luci_datatype(tensor.type));
264
265   assert(tensor.shape_signature.size() == 0 ||
266          tensor.shape_signature.size() == tensor.shape.size());
267
268   std::vector<int32_t> dims = tensor.shape; // in NHWC
269   node->rank(dims.size());
270   for (uint32_t r = 0; r < dims.size(); ++r)
271   {
272     if (tensor.shape_signature.size() > 0 && tensor.shape_signature.at(r) == -1)
273       node->dim(r).unset();
274     else
275       node->dim(r).set(dims[r]);
276   }
277
278   const auto *quantization = tensor.quantization.get();
279   if (quantization != nullptr)
280   {
281     auto quantparam = luci_quantparam(quantization);
282     if (quantparam)
283       node->quantparam(std::move(quantparam));
284   }
285
286   const auto *sparsity = tensor.sparsity.get();
287   if (sparsity != nullptr)
288   {
289     auto sparsityparam = luci_sparsityparam(sparsity);
290     if (sparsityparam)
291       node->sparsityparam(std::move(sparsityparam));
292   }
293 }
294
295 circle::BuiltinOperator CircleReader::builtin_code(const circle::OperatorT &op) const
296 {
297   const auto &op_codes = opcodes();
298   uint32_t index = op.opcode_index;
299   assert(index < op_codes.size());
300   const circle::OperatorCodeT &opcode = *op_codes[index];
301
302   return opcode.builtin_code;
303 }
304
305 std::string CircleReader::opcode_name(const circle::OperatorT &op) const
306 {
307   const auto &op_codes = opcodes();
308   uint32_t index = op.opcode_index;
309   assert(index < op_codes.size());
310   const circle::OperatorCodeT &opcode = *op_codes[index];
311
312   if (!is_valid(opcode))
313   {
314     std::ostringstream oss;
315     oss << "(invalid: " << index << ")";
316     return oss.str();
317   }
318
319   return ::luci::opcode_name(opcode);
320 }
321
322 bool CircleReader::parse(const circle::Model *model)
323 {
324   assert(model != nullptr);
325
326   _model.reset(model->UnPack());
327
328   // for direct pointer access
329   _model_ptr = model;
330
331   return true;
332 }
333
334 bool CircleReader::select_subgraph(uint32_t sgindex)
335 {
336   if (_model->subgraphs.size() <= sgindex)
337   {
338     assert(false);
339     return false;
340   }
341
342   _current_subgraph = _model->subgraphs[sgindex].get();
343
344   // for direct pointer access
345   auto subgraphs = _model_ptr->subgraphs();
346   const circle::SubGraph *subgraph = (*subgraphs)[sgindex];
347
348   _tensors_ptr = subgraph->tensors();
349
350   return true;
351 }
352
353 } // namespace luci