ONE - On-device Neural Engine
Loading...
Searching...
No Matches
CircleModel.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 <cassert>
18#include <iostream>
19#include <map>
20#include <memory>
21
22#include "CircleModel.h"
23#include "DataLookup.h"
24
26
27namespace tflite2circle
28{
29
30template <> void Offset<MetaDataBufferLink>::build(const TFLFlatBufVec *tflite_flatbuffer_vec)
31{
32 if (tflite_flatbuffer_vec == nullptr)
33 return;
34 std::vector<int32_t> metadata_buffer_vec{tflite_flatbuffer_vec->begin(),
35 tflite_flatbuffer_vec->end()};
36 _circle_flatbuffer_vec_offset = _fb->CreateVector(metadata_buffer_vec);
37}
38
39template <> void Offset<BufferLink>::build(const TFLFlatBufVec *tflite_flatbuffer_vec)
40{
41 std::vector<flatbuffers::Offset<circle::Buffer>> buffers_vec;
42
43 for (auto it : *tflite_flatbuffer_vec)
44 {
46 const auto *tflbuff_data = it->data();
47 const auto tflbuff_offset = it->offset();
48 const auto tflbuff_size = it->size();
49 // NOTE Current imlementation assumes "size of tflite >= size of circle"
50 // so that if tflite uses offset field, circle will use it too.
51 // this assumption is chosen cause (a) expereince with the file size showed this result,
52 // (b) to reduce code changes. if not, we will have to go in two pass, (1) produce flatbuffers
53 // and check size and if size > 2G then (2) restart produce flatbuffres with setting offset,
54 // size attributes.
55 // NOTE we cannot use offset/size as-is from tflite as "tflite size" != "circle size"
56 if (tflbuff_offset > 1)
57 {
58 assert(_buffer_data_map && _file_raw);
59 if (_buffer_data_map && _file_raw)
60 {
61 int32_t buffer_index = buffers_vec.size();
62
63 auto *file_data_ptr = reinterpret_cast<const uint8_t *>(_file_raw->data()) + tflbuff_offset;
64 std::vector<uint8_t> buffer_data(file_data_ptr, file_data_ptr + tflbuff_size);
65 _buffer_data_map->emplace(buffer_index, buffer_data);
66
67 // NOTE about below 0, 1, 1
68 // 0 is to indicate that this data is dummy and real one will be saved after flatbuffers
69 // area. 1, 1 will be updated at finilize() method below, after all flatbuffers data
70 // are generated, so that we can then get the valid offset of this Buffer data.
71 // if we meet offset as 1 then update failed and this file is invalid.
72 auto buffer = circle::CreateBuffer(*_fb.get(), 0 /* data */, 1 /* offset */, 1 /* size */);
73 buffers_vec.emplace_back(buffer);
74 }
75 }
76 else
77 {
78 assert(tflbuff_offset != 1);
79 if (tflbuff_data)
80 {
81 std::vector<uint8_t> data_vec{tflbuff_data->begin(), tflbuff_data->end()};
82 buffer_data = _fb->CreateVector(data_vec);
83 }
84 circle::BufferBuilder circle_buffer_builder{*_fb};
85 circle_buffer_builder.add_data(buffer_data);
86 auto circle_buffers = circle_buffer_builder.Finish();
87 buffers_vec.emplace_back(circle_buffers);
88 }
89 }
90 _circle_flatbuffer_vec_offset = _fb->CreateVector(buffers_vec);
91}
92
93template <> void Offset<SubGraphLink>::build(const TFLFlatBufVec *tflite_flatbuffer_vec)
94{
95 std::vector<flatbuffers::Offset<circle::SubGraph>> subgprahs_vec;
96
97 int32_t subgraph_index = 0;
98
99 for (auto it_sg : *tflite_flatbuffer_vec)
100 {
101 // tensors of subgraph
102 std::vector<flatbuffers::Offset<circle::Tensor>> tensor_vec;
103
104 auto tflite_tensors = it_sg->tensors();
105 for (auto it : *tflite_tensors)
106 {
107 // shape
109 if (it->shape())
110 {
111 auto shape_vec = std::vector<int32_t>({it->shape()->begin(), it->shape()->end()});
112 shape = _fb->CreateVector(shape_vec);
113 }
114 // name
116 if (it->name())
117 name = _fb->CreateString(it->name()->str());
118 // quantization
120 if (it->quantization())
121 {
122 std::vector<float> tfmin;
123 std::vector<float> tfmax;
124 std::vector<float> tfscale;
125 std::vector<int64_t> tfzerop;
130 int32_t quantized_dimension = it->quantization()->quantized_dimension();
131
132 if (it->quantization()->min() && it->quantization()->max())
133 {
134 auto rmin = it->quantization()->min();
135 auto rmax = it->quantization()->max();
136 tfmin = std::vector<float>{rmin->begin(), rmin->end()};
137 tfmax = std::vector<float>{rmax->begin(), rmax->end()};
138 min = _fb->CreateVector(tfmin);
139 max = _fb->CreateVector(tfmax);
140 }
141
142 if (it->quantization()->scale() && it->quantization()->zero_point())
143 {
144 auto rs = it->quantization()->scale();
145 auto rz = it->quantization()->zero_point();
146 tfscale = std::vector<float>{rs->begin(), rs->end()};
147 tfzerop = std::vector<int64_t>{rz->begin(), rz->end()};
148 scale = _fb->CreateVector(tfscale);
149 zero_point = _fb->CreateVector(tfzerop);
150 }
151
152 quantization = circle::CreateQuantizationParameters(*_fb, min, max, scale, zero_point,
153 circle::QuantizationDetails_NONE, 0,
154 quantized_dimension);
155 }
156 // is_variable
157 bool is_variable = it->is_variable();
158
160 // sparsity
161 if (it->sparsity())
162 {
166 dim_metadata;
167
168 // traversal_order
169 if (it->sparsity()->traversal_order())
170 {
171 auto traversal_order_vec = std::vector<int32_t>{
172 it->sparsity()->traversal_order()->begin(), it->sparsity()->traversal_order()->end()};
173 traversal_order = _fb->CreateVector(traversal_order_vec);
174 }
175
176 // block_map
177 if (it->sparsity()->block_map())
178 {
179 auto block_map_vec = std::vector<int32_t>{it->sparsity()->block_map()->begin(),
180 it->sparsity()->block_map()->end()};
181 block_map = _fb->CreateVector(block_map_vec);
182 }
183
184 // dim_metadata
185 std::vector<flatbuffers::Offset<circle::DimensionMetadata>> dim_metadata_vec;
186 auto tflite_dim_metadata = it->sparsity()->dim_metadata();
187 for (auto it : *tflite_dim_metadata)
188 {
189 // array_segments
190 auto tflite_array_segments_type = it->array_segments_type();
191 auto circle_array_segments =
192 get_circle_sparse_index_vector(*_fb, it->array_segments(), tflite_array_segments_type);
193 auto circle_array_segments_type =
194 get_circle_sparse_index_vector_type(tflite_array_segments_type);
195
196 // array_indices
197 auto tflite_array_indices_type = it->array_indices_type();
198 auto circle_array_indices =
199 get_circle_sparse_index_vector(*_fb, it->array_indices(), tflite_array_indices_type);
200 auto circle_array_indices_type =
201 get_circle_sparse_index_vector_type(tflite_array_indices_type);
202
203 auto circle_dim_metadata_builder = circle::DimensionMetadataBuilder{*_fb};
204
205 circle_dim_metadata_builder.add_format(get_circle_dimension_type(it->format()));
206 circle_dim_metadata_builder.add_dense_size(it->dense_size());
207 circle_dim_metadata_builder.add_array_segments(circle_array_segments);
208 circle_dim_metadata_builder.add_array_segments_type(circle_array_segments_type);
209 circle_dim_metadata_builder.add_array_indices(circle_array_indices);
210 circle_dim_metadata_builder.add_array_indices_type(circle_array_indices_type);
211 auto dim_metadata = circle_dim_metadata_builder.Finish();
212 dim_metadata_vec.emplace_back(dim_metadata);
213 }
214 dim_metadata = _fb->CreateVector(dim_metadata_vec);
215
216 sparsity = circle::CreateSparsityParameters(*_fb, traversal_order, block_map, dim_metadata);
217 }
218
219 // shape signature
221 if (it->shape_signature())
222 {
223 auto shape_signature_vec =
224 std::vector<int32_t>({it->shape_signature()->begin(), it->shape_signature()->end()});
225 shape_signature = _fb->CreateVector(shape_signature_vec);
226 }
227
228 circle::TensorBuilder tensor_builder{*_fb};
229 tensor_builder.add_shape(shape);
230 tensor_builder.add_type(get_circle_tensortype(it->type()));
231 tensor_builder.add_buffer(it->buffer());
232 tensor_builder.add_name(name);
233 tensor_builder.add_quantization(quantization);
234 tensor_builder.add_is_variable(is_variable);
235 tensor_builder.add_sparsity(sparsity);
236 tensor_builder.add_shape_signature(shape_signature);
237 auto tensor = tensor_builder.Finish();
238 tensor_vec.emplace_back(tensor);
239 }
240 auto circle_tensors = _fb->CreateVector(tensor_vec);
241
242 // inputs of subgraph
243 auto tflite_inputs = it_sg->inputs();
244 std::vector<int32_t> input_vec{tflite_inputs->begin(), tflite_inputs->end()};
245
246 // apply signature_def to input tensor index so that input orders follow like tensorflow lite
247 // interpreter._get_full_signature_list() method, which is ordered(sorted) in name
248 // NOTE we do not need this when circle format supports signature_def
249 if (_tfl_signature_def_offsets != nullptr)
250 {
251 for (auto it_signdef : *_tfl_signature_def_offsets)
252 {
253 if (it_signdef->subgraph_index() == subgraph_index)
254 {
255 auto inputs = it_signdef->inputs();
256 assert(inputs->size() == input_vec.size());
257
258 std::map<std::string, uint32_t> map_name_index;
259 for (auto it_tm : *inputs)
260 {
261 map_name_index[it_tm->name()->str()] = it_tm->tensor_index();
262 }
263 uint32_t input_vec_idx = 0;
264 for (auto &item : map_name_index)
265 {
266 input_vec[input_vec_idx++] = item.second;
267 }
268 }
269 }
270 }
271
272 auto circle_inputs = _fb->CreateVector(input_vec);
273
274 // outputs of subgraph
275 auto tflite_outputs = it_sg->outputs();
276 std::vector<int32_t> output_vec{tflite_outputs->begin(), tflite_outputs->end()};
277
278 if (_tfl_signature_def_offsets != nullptr)
279 {
280 // apply SignatureDef
281 for (auto it_signdef : *_tfl_signature_def_offsets)
282 {
283 if (it_signdef->subgraph_index() == subgraph_index)
284 {
285 auto outputs = it_signdef->outputs();
286 assert(outputs->size() == output_vec.size());
287
288 std::map<std::string, uint32_t> map_name_index;
289 for (auto it_tm : *outputs)
290 {
291 map_name_index[it_tm->name()->str()] = it_tm->tensor_index();
292 }
293 uint32_t output_vec_idx = 0;
294 for (auto &item : map_name_index)
295 {
296 output_vec[output_vec_idx++] = item.second;
297 }
298 }
299 }
300 }
301
302 auto circle_outputs = _fb->CreateVector(output_vec);
303
304 // operators of subgraph
305 std::vector<flatbuffers::Offset<circle::Operator>> operator_vec;
306
307 auto tflite_operators = it_sg->operators();
308 if (tflite_operators != nullptr)
309 {
310 for (auto it : *tflite_operators)
311 {
312 // inputs
313 std::vector<int32_t> input_vec{it->inputs()->begin(), it->inputs()->end()};
314 auto circle_inputs = _fb->CreateVector(input_vec);
315 // outputs
316 std::vector<int32_t> output_vec{it->outputs()->begin(), it->outputs()->end()};
317 auto circle_outputs = _fb->CreateVector(output_vec);
318 // builtin options
319 auto circle_builtin_options = get_circle_builtin_options(*_fb, it);
320 auto circle_builtin_options_type = get_circle_builtin_options_type(it);
321 // custom options
323 if (it->custom_options())
324 {
325 std::vector<uint8_t> custom_options_vec{it->custom_options()->begin(),
326 it->custom_options()->end()};
327 circle_custom_options = _fb->CreateVector(custom_options_vec);
328 }
329 // custom options format
330 // TODO Make get_circle_custom_options_format
331 assert(it->custom_options_format() == tflite::CustomOptionsFormat_FLEXBUFFERS);
332 auto circle_custom_options_format = circle::CustomOptionsFormat_FLEXBUFFERS;
333
334 circle::OperatorBuilder operator_builder{*_fb};
335 operator_builder.add_opcode_index(it->opcode_index());
336 operator_builder.add_inputs(circle_inputs);
337 operator_builder.add_outputs(circle_outputs);
338 operator_builder.add_builtin_options(circle_builtin_options);
339 operator_builder.add_builtin_options_type(circle_builtin_options_type);
340 operator_builder.add_custom_options(circle_custom_options);
341 operator_builder.add_custom_options_format(circle_custom_options_format);
342 // TODO mutating_variable_inputs
343 auto opeartor = operator_builder.Finish();
344 operator_vec.emplace_back(opeartor);
345 }
346 }
347 auto circle_operators = _fb->CreateVector(operator_vec);
348
349 // name of subgraph
350 auto subgraphs_name = _fb->CreateString(it_sg->name());
351
352 // subgraphs
353 auto circle_subgraph_builder = circle::SubGraphBuilder{*_fb};
354
355 circle_subgraph_builder.add_tensors(circle_tensors);
356 circle_subgraph_builder.add_inputs(circle_inputs);
357 circle_subgraph_builder.add_outputs(circle_outputs);
358 circle_subgraph_builder.add_operators(circle_operators);
359 circle_subgraph_builder.add_name(subgraphs_name);
360
361 auto circle_subgraph = circle_subgraph_builder.Finish();
362 subgprahs_vec.emplace_back(circle_subgraph);
363
364 // next subgraph
365 subgraph_index = subgraph_index + 1;
366 }
367 _circle_flatbuffer_vec_offset = _fb->CreateVector(subgprahs_vec);
368}
369
370template <> void Offset<OperatorCodeLink>::build(const TFLFlatBufVec *tflite_flatbuffer_vec)
371{
372 std::vector<flatbuffers::Offset<circle::OperatorCode>> operator_code_vec;
373
374 for (auto it : *tflite_flatbuffer_vec)
375 {
376 auto custom_code = _fb->CreateString(it->custom_code());
377 circle::OperatorCodeBuilder operator_code_builder{*_fb};
378 auto de_code = it->deprecated_builtin_code();
379 auto bt_code = it->builtin_code();
380
381 // There are two builtin codes (deprecated_builtin, (extended) builtin)
382 // deprecated builtin code uses 0~126
383 // extended builtin code uses 127~
384 // NOTE 127 = BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES
385 if (de_code >= 0 and de_code < 127)
386 {
387 // Use deprecated builtin opcode.
388 auto cir_de_code = get_circle_builtin_code(de_code);
389 auto cir_bt_code = get_circle_builtin_code(bt_code);
390 // correct bt_code where bt_code == 0 for old tflite format
391 if (cir_bt_code == 0)
392 cir_bt_code = static_cast<circle::BuiltinOperator>(cir_de_code);
393 operator_code_builder.add_deprecated_builtin_code(cir_de_code);
394 operator_code_builder.add_builtin_code(cir_bt_code);
395 }
396 else
397 {
398 // Use extended builtin opcode
399 // Set 127 (PLACEHOLDER_FOR_GREATER_OP_CODES) for deprecated builtin code
400 auto cir_bt_code = get_circle_builtin_code(bt_code);
401 operator_code_builder.add_deprecated_builtin_code(
402 tflite::BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES);
403 operator_code_builder.add_builtin_code(cir_bt_code);
404 }
405 operator_code_builder.add_custom_code(custom_code);
406 operator_code_builder.add_version(it->version());
407 auto code = operator_code_builder.Finish();
408 operator_code_vec.emplace_back(code);
409 }
410 _circle_flatbuffer_vec_offset = _fb->CreateVector(operator_code_vec);
411}
412
413CircleModel::CircleModel(FlatBufBuilder &fb, const std::vector<char> &fr)
414 : _version{0}, _description{fb->CreateString("ONE-tflite2circle")}, _fb{fb}, _file_raw{fr}
415{
416 // NOTHING TODO
417}
418
419void CircleModel::load_offsets(const tflite::Model *tfl_model)
420{
421 _operator_codes_offset = std::make_unique<Offset<OperatorCodeLink>>(_fb);
422 _subGraphs_offset = std::make_unique<Offset<SubGraphLink>>(_fb);
423 _buffers_offset = std::make_unique<Offset<BufferLink>>(_fb);
424 _metadata_buffer_offset = std::make_unique<Offset<MetaDataBufferLink>>(_fb);
425
426 _subGraphs_offset->set_signature_defs(tfl_model->signature_defs());
427 _buffers_offset->set_buffer_data_map(&_buffer_data_map);
428 _buffers_offset->set_file_raw(&_file_raw);
429
430 _operator_codes_offset->build(tfl_model->operator_codes());
431 _subGraphs_offset->build(tfl_model->subgraphs());
432 _buffers_offset->build(tfl_model->buffers());
433 _metadata_buffer_offset->build(tfl_model->metadata_buffer());
434}
435
437{
438 circle::ModelBuilder model_builder{*_fb};
439
440 model_builder.add_version(_version);
441 model_builder.add_description(_description);
442 model_builder.add_operator_codes(_operator_codes_offset->offset());
443 model_builder.add_subgraphs(_subGraphs_offset->offset());
444 model_builder.add_buffers(_buffers_offset->offset());
445 model_builder.add_metadata_buffer(_metadata_buffer_offset->offset());
446
447 auto model = model_builder.Finish();
448 circle::FinishModelBuffer(*_fb, model);
449}
450
452{
453 if (_buffer_data_map.empty())
454 return;
455
456 auto align16 = [](size_t &v) {
457 while (v % 16 != 0)
458 v++;
459 };
460
461 // get total memory for flatbuffer + all buffer_data
462 size_t result_size = _fb->GetSize();
463 align16(result_size);
464 for (auto &it : _buffer_data_map)
465 {
466 BufferData &buffer_data = it.second;
467 result_size += buffer_data.size();
468 align16(result_size);
469 }
470 align16(result_size);
471 result_size += 16; // for safety
472
473 std::string result;
474 const char *buff_ptr = reinterpret_cast<const char *>(_fb->GetBufferPointer());
475
476 auto padalign16 = [](std::string &str) {
477 while (str.size() % 16 != 0)
478 str += '\0';
479 };
480
481 result.reserve(result_size);
482 result.append(buff_ptr, _fb->GetSize());
483
484 auto mutable_model = circle::GetMutableModel(result.data());
485 auto mutable_buffers = mutable_model->mutable_buffers();
486
487 // pad to be 16 bytes aligned
488 padalign16(result);
489 for (auto &it : _buffer_data_map)
490 {
491 int32_t buffer_index = it.first;
492 BufferData &buffer_data = it.second;
493 uint64_t offset = result.size();
494 uint64_t size = buffer_data.size();
495
496 circle::Buffer *mutable_buffer = mutable_buffers->GetMutableObject(buffer_index);
497 mutable_buffer->mutate_offset(offset);
498 mutable_buffer->mutate_size(size);
499
500 result.append(buffer_data.begin(), buffer_data.end());
501 padalign16(result);
502 }
503 padalign16(result);
504
505 // use final result
506 _fb_data_with_ext = result;
507}
508
509const char *CircleModel::base(void) const
510{
511 if (_buffer_data_map.empty())
512 return reinterpret_cast<const char *>(_fb->GetBufferPointer());
513 return reinterpret_cast<const char *>(_fb_data_with_ext.data());
514}
515
516size_t CircleModel::size(void) const
517{
518 if (_buffer_data_map.empty())
519 return _fb->GetSize();
520 return _fb_data_with_ext.size();
521}
522
523} // namespace tflite2circle
void model_build(void) const
size_t size(void) const
const char * base(void) const
void load_offsets(const tflite::Model *tfl_model)
void build(const TFLFlatBufVec *tflite_flatbuffer_vec)
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
circle::SparseIndexVector get_circle_sparse_index_vector_type(const tflite::SparseIndexVector &tfl_sparse_index_vector_type)
Returns circle SparseIndexVector type according to tflite.
std::unique_ptr< flatbuffers::FlatBufferBuilder > FlatBufBuilder
Definition CircleModel.h:32
circle::BuiltinOptions get_circle_builtin_options_type(const tflite::Operator *op)
Returns circle builtin_options_type according to tflite.
circle::DimensionType get_circle_dimension_type(tflite::DimensionType tfl_dim_type)
Returns circle DimensionType according to tflite.
std::vector< uint8_t > BufferData
Definition CircleModel.h:58
flatbuffers::Offset< void > get_circle_builtin_options(flatbuffers::FlatBufferBuilder &fb, const tflite::Operator *op)
Returns circle builtin_options according to tflite.
circle::BuiltinOperator get_circle_builtin_code(tflite::BuiltinOperator tfl_bop)
Returns circle builtin_code according to tflite.
circle::TensorType get_circle_tensortype(tflite::TensorType tfl_tt)
Returns circle TensorType according to tflite.
flatbuffers::Offset< void > get_circle_sparse_index_vector(flatbuffers::FlatBufferBuilder &fb, const void *v_array, const tflite::SparseIndexVector &tfl_sparse_index_vector_type)
Returns circle SparseIndexVector according to tflite.
int32_t begin[5]
Definition Slice.cpp:33