ONE - On-device Neural Engine
Loading...
Searching...
No Matches
CircleTensorExporter.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
18
19#include "CircleExporterUtils.h"
20
21#include <luci/IR/CircleNodes.h>
25#include <luci/Log.h>
26
27#include <loco/IR/Algorithm.h>
31#include <oops/InternalExn.h>
32
33#include <string.h>
34
35using namespace circle;
36using namespace flatbuffers;
37
38namespace
39{
40
41using namespace luci;
42
43class CircleTensorInfo
44{
45public:
46 CircleTensorInfo() = default;
47
48public:
49 void name(const std::string &name) { _name = name; }
50 const std::string &name(void) const { return _name; }
51
52public:
53 const circle::TensorType &dtype(void) const { return _dtype; }
54 void dtype(const circle::TensorType &dtype) { _dtype = dtype; }
55
56 const ShapeDescription &shape(void) const { return _shape; }
57 void shape(const ShapeDescription &shape) { _shape = shape; }
58
59 luci::ShapeStatus shape_status(void) const { return _shape_status; }
60 void shape_status(luci::ShapeStatus ss) { _shape_status = ss; }
61
62public:
63 luci::CircleConst *content(void) const { return _content; }
64 void content(luci::CircleConst *c) { _content = c; }
65
66 luci::CircleQuantParam *quantparam(void) const { return _quantparam; }
67 void quantparam(luci::CircleQuantParam *qp) { _quantparam = qp; }
68
69 luci::CircleMXQuantParam *mx_quantparam(void) const { return _mx_quantparam; }
70 void mx_quantparam(luci::CircleMXQuantParam *qp) { _mx_quantparam = qp; }
71
72 luci::SparsityParam *sparsityparam(void) const { return _sparsityparam; }
73 void sparsityparam(luci::SparsityParam *sp) { _sparsityparam = sp; }
74
75 bool is_variable(void) const { return _is_variable; }
76 void is_variable(bool v) { _is_variable = v; }
77
78private:
79 std::string _name;
80
81 circle::TensorType _dtype{circle::TensorType_FLOAT32};
82 ShapeDescription _shape{};
84
85 luci::CircleConst *_content = nullptr;
86 luci::CircleQuantParam *_quantparam = nullptr;
87 luci::CircleMXQuantParam *_mx_quantparam = nullptr;
88 luci::SparsityParam *_sparsityparam = nullptr;
89
90 bool _is_variable = false;
91};
92
93class CircleTensorContext
94{
95public:
96 CircleTensorContext() = default;
97
98public:
99 void emplace_back(CircleTensorInfo &ti)
100 {
101 assert(_names.find(ti.name()) == _names.end());
102 _tis.emplace_back(ti);
103 _names.insert(ti.name());
104 }
105 size_t size(void) const { return _tis.size(); }
106 std::vector<CircleTensorInfo>::iterator begin(void) { return _tis.begin(); }
107 std::vector<CircleTensorInfo>::iterator end(void) { return _tis.end(); }
108
109public:
110 bool exist(const std::string &name) const { return _names.find(name) != _names.end(); }
111
112private:
113 std::vector<CircleTensorInfo> _tis;
114 std::set<std::string> _names;
115};
116
117struct NoOpDetector final : public luci::CircleNodeMutableVisitor<bool>
118{
119 // Input is Virtual but does produce a Tensor
120 // Output is Virtual that does not produce any Tensor
121 bool visit(luci::CircleOutput *) final { return true; }
122 bool visit(luci::CircleOutputExclude *) final { return true; }
123
124 // Return false by default
125 bool visit(luci::CircleNode *) final { return false; }
126};
127
128void allocateCircleTensorInfo(CircleNode *node, CircleTensorContext &ctx)
129{
130 LOGGER(l);
131
132 auto tensor_index = static_cast<CircleTensorIndex>(ctx.size());
133 // TODO Use Graph-level metadata for Input & Output
134 std::string tensor_name = node->name();
135 // NOTE tensor_name maybe empty. this assertion will alert when this happens.
136 // currently we require tensor should have a name.
137 // TODO if this breaks, fix the cause or permit empty tensor_name.
138 assert(!tensor_name.empty());
139 if (ctx.exist(tensor_name))
140 {
141 // NOTE this should assign unique name for a Tensor.
142 tensor_name = tensor_name + "_" + std::to_string(tensor_index);
143 assert(!ctx.exist(tensor_name));
144 }
145 INFO(l) << "[luci] Tensor for " << tensor_name << ": " << tensor_index << std::endl;
146
147 CircleTensorInfo tensor_info;
148
149 tensor_info.name(tensor_name);
150 tensor_info.dtype(to_circle_tensortype(node->dtype()));
151 if (node->shape_status() == ShapeStatus::VALID)
152 tensor_info.shape(to_shape_description(node));
153 tensor_info.shape_status(node->shape_status());
154
155 tensor_info.content(dynamic_cast<luci::CircleConst *>(node));
156 tensor_info.quantparam(node->quantparam());
157 tensor_info.mx_quantparam(node->mx_quantparam());
158 tensor_info.sparsityparam(node->sparsityparam());
159
160 tensor_info.is_variable(dynamic_cast<luci::CircleVariable *>(node) != nullptr);
161
162 set_tensor_index(node, tensor_index);
163
164 ctx.emplace_back(tensor_info);
165}
166
167class MultiOutputDetector final : public luci::CircleNodeMutableVisitor<bool>
168{
169public:
170 MultiOutputDetector(CircleTensorContext &ctx) : _ctx(ctx) {}
171
172private:
173 void store_outputs(luci::CircleNode *node, uint32_t count)
174 {
175 auto outs = loco::succs(node);
176 assert(outs.size() == count);
177 (void)count; // for unused variable error in release build
178 for (auto out : outs)
179 {
180 auto circle_out = loco::must_cast<luci::CircleNode *>(out);
181 allocateCircleTensorInfo(circle_out, _ctx);
182 }
183 set_tensor_index(node, -1);
184 }
185
186public:
187 bool visit(luci::CircleBidirectionalSequenceLSTMOut *) final { return true; }
188 bool visit(luci::CircleCustomOut *) final { return true; }
189 bool visit(luci::CircleIfOut *) final { return true; }
190 bool visit(luci::CircleNonMaxSuppressionV4Out *) final { return true; }
191 bool visit(luci::CircleNonMaxSuppressionV5Out *) final { return true; }
192 bool visit(luci::CircleSplitOut *) final { return true; }
193 bool visit(luci::CircleSplitVOut *) final { return true; }
194 bool visit(luci::CircleTopKV2Out *) final { return true; }
195 bool visit(luci::CircleUnpackOut *) final { return true; }
196 bool visit(luci::CircleUniqueOut *) final { return true; }
197 bool visit(luci::CircleWhileOut *) final { return true; }
198
200 {
201 if (node->merge_outputs())
202 {
203 store_outputs(node, 1);
204 }
205 else
206 {
207 store_outputs(node, 2);
208 }
209 return true;
210 }
211
212 bool visit(luci::CircleCustom *node) final
213 {
214 store_outputs(node, node->numOutputs());
215 return true;
216 }
217
218 bool visit(luci::CircleIf *node) final
219 {
220 store_outputs(node, node->output_count());
221 return true;
222 }
223
224 bool visit(luci::CircleNonMaxSuppressionV4 *node) final
225 {
226 store_outputs(node, 2);
227 return true;
228 }
229
230 bool visit(luci::CircleNonMaxSuppressionV5 *node) final
231 {
232 store_outputs(node, 3);
233 return true;
234 }
235
236 bool visit(luci::CircleSplit *node) final
237 {
238 store_outputs(node, uint32_t(node->num_split()));
239 return true;
240 }
241
242 bool visit(luci::CircleSplitV *node) final
243 {
244 store_outputs(node, uint32_t(node->num_split()));
245 return true;
246 }
247
248 bool visit(luci::CircleTopKV2 *node) final
249 {
250 store_outputs(node, 2);
251 return true;
252 }
253
254 bool visit(luci::CircleUnpack *node) final
255 {
256 store_outputs(node, node->num());
257 return true;
258 }
259
260 bool visit(luci::CircleUnique *node) final
261 {
262 store_outputs(node, 2);
263 return true;
264 }
265
266 bool visit(luci::CircleWhile *node) final
267 {
268 store_outputs(node, node->output_count());
269 return true;
270 }
271
272 // Return false by default
273 bool visit(luci::CircleNode *) final { return false; }
274
275private:
276 CircleTensorContext &_ctx;
277};
278
279void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx)
280{
281 if (node == nullptr)
282 throw std::runtime_error("allocateCIrcleTensor Failed : node is nullptr");
283
284 auto isNoOp = [](loco::Node *node) {
285 if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
286 {
287 NoOpDetector d;
288 return circle_node->accept(&d);
289 }
290 return false;
291 };
292
293 if (isNoOp(node))
294 {
295 set_tensor_index(node, -1);
296 return;
297 }
298
299 // TODO revise this when loco supports multiple outputs
300 // NOTE this will store all virtual output tensors and skip for the real node
301 if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
302 {
303 MultiOutputDetector d(ctx);
304 if (circle_node->accept(&d))
305 return;
306 }
307
308 allocateCircleTensorInfo(node, ctx);
309}
310
311} // namespace
312
313namespace
314{
315
317 const ShapeDescription &shape)
318{
319 assert(shape._rank_known && "unknown number of dimensions is not supported");
320
321 std::vector<int32_t> encoded_shape;
322 encoded_shape.resize(shape._dims.size());
323 for (uint32_t i = 0; i < shape._dims.size(); ++i)
324 encoded_shape.at(i) = shape._dims.at(i) == -1 ? 1 : shape._dims.at(i);
325
326 return builder.CreateVector(encoded_shape);
327}
328
329flatbuffers::Offset<Vector<int32_t>> encodeShapeSignature(FlatBufferBuilder &builder,
330 const ShapeDescription &shape)
331{
332 assert(shape._rank_known && "unknown number of dimensions is not supported");
333
334 // shape_signature is set if and only if at least one of dimensions are unknown.
335 for (uint32_t i = 0; i < shape._dims.size(); ++i)
336 if (shape._dims.at(i) == -1)
337 return builder.CreateVector(shape._dims);
338
340}
341
343{
344 return CreateBuffer(builder);
345}
346
347template <typename NodeT>
349 SerializedModelData &, NodeT *)
350{
351 return CreateBuffer(builder);
352}
353
354template <loco::DataType DT>
356encodeOpBufferByDType(FlatBufferBuilder &builder, SerializedModelData &md, luci::CircleConst *c)
357{
358 using NativeType = typename loco::DataTypeImpl<DT>::Type;
359
360 std::vector<NativeType> raw_data;
361 const uint32_t size = c->size<DT>();
362 raw_data.reserve(size);
363 for (uint32_t i = 0; i < size; ++i)
364 {
365 raw_data.push_back(c->at<DT>(i));
366 }
367 const size_t raw_size = size * sizeof(NativeType);
368
369 if (md._ext_buffer)
370 {
371 // TODO optimize this if this operation takes long or much memory
373 buffer_data.resize(raw_size);
374 std::memcpy(buffer_data.data(), raw_data.data(), raw_size);
375
376 int32_t buffer_index = md._buffers.size();
377 md._buffer_data_map.emplace(buffer_index, buffer_data);
378
379 // create fake indicator buffer
380 return circle::CreateBuffer(builder, 0 /* data */, 1 /* offset */, 1 /* size */);
381 }
382 if (check_size_limit(builder, raw_size))
383 {
384 md._require_ext_buffer = true;
385 return md._empty_buffer;
386 }
387
388 auto array_offset = builder.CreateVector(reinterpret_cast<uint8_t *>(raw_data.data()), raw_size);
389 return CreateBuffer(builder, array_offset);
390}
391
392template <>
394encodeOpBufferByDType<loco::DataType::STRING>(FlatBufferBuilder &builder, SerializedModelData &,
396{
397 const uint32_t count = c->size<loco::DataType::STRING>();
398 uint32_t raw_size = sizeof(int32_t) * (count + 2);
399 for (uint32_t i = 0; i < count; ++i)
400 {
401 auto &value = c->at<loco::DataType::STRING>(i);
402 raw_size += value.length();
403 }
404
405 // serialize string data
406 // int32_t count
407 // int32_t offsets[count + 1]
408 // string values[count]
409 std::vector<uint8_t> raw_data;
410 raw_data.reserve(raw_size);
411
412 auto *i32d = reinterpret_cast<int32_t *>(raw_data.data());
413 int32_t start = sizeof(int32_t) * (count + 2);
414 int32_t offset = start;
415 std::vector<int32_t> offsets;
416
417 *i32d++ = count;
418 *i32d++ = start;
419 offsets.push_back(start);
420 for (uint32_t i = 0; i < count; ++i)
421 {
422 auto &value = c->at<loco::DataType::STRING>(i);
423 offset += value.length();
424 *i32d++ = offset;
425 offsets.push_back(offset);
426 }
427
428 auto *data = reinterpret_cast<uint8_t *>(i32d);
429 for (uint32_t i = 0; i < count; ++i)
430 {
431 int32_t length = offsets[i + 1] - offsets[i];
432 auto &value = c->at<loco::DataType::STRING>(i);
433 memcpy(data, value.c_str(), length);
434 data += length;
435 }
436
437 auto array_offset = builder.CreateVector(reinterpret_cast<uint8_t *>(raw_data.data()), raw_size);
438 return CreateBuffer(builder, array_offset);
439}
440
441template <loco::DataType DT>
443encodeOpBufferPack4bit(FlatBufferBuilder &builder, SerializedModelData &, luci::CircleConst *c)
444{
445 const uint32_t size = c->size<DT>();
446 const uint32_t raw_size = (size + 1) / 2;
447 std::vector<uint8_t> raw_data(raw_size);
448
449 for (uint32_t i = 0; i < raw_size; ++i)
450 {
451 uint32_t sidx = i * 2;
452 uint8_t data = static_cast<uint8_t>(c->at<DT>(sidx));
453 raw_data[i] = data & 0x0f;
454 sidx++;
455 if (sidx < size)
456 {
457 data = static_cast<uint8_t>(c->at<DT>(sidx));
458 raw_data[i] |= data << 4;
459 }
460 }
461
462 auto array_offset = builder.CreateVector(raw_data.data(), raw_size);
463 return CreateBuffer(builder, array_offset);
464}
465
466template <>
469{
470 switch (c->dtype())
471 {
472 case loco::DataType::FLOAT32:
473 return encodeOpBufferByDType<loco::DataType::FLOAT32>(builder, md, c);
474 case loco::DataType::S4:
475 return encodeOpBufferPack4bit<loco::DataType::S4>(builder, md, c);
476 case loco::DataType::S8:
477 return encodeOpBufferByDType<loco::DataType::S8>(builder, md, c);
478 case loco::DataType::S16:
479 return encodeOpBufferByDType<loco::DataType::S16>(builder, md, c);
480 case loco::DataType::S32:
481 return encodeOpBufferByDType<loco::DataType::S32>(builder, md, c);
482 case loco::DataType::S64:
483 return encodeOpBufferByDType<loco::DataType::S64>(builder, md, c);
484 case loco::DataType::U4:
485 return encodeOpBufferPack4bit<loco::DataType::U4>(builder, md, c);
486 case loco::DataType::U8:
487 return encodeOpBufferByDType<loco::DataType::U8>(builder, md, c);
488 case loco::DataType::BOOL:
489 return encodeOpBufferByDType<loco::DataType::BOOL>(builder, md, c);
490 case loco::DataType::STRING:
491 return encodeOpBufferByDType<loco::DataType::STRING>(builder, md, c);
492 default:
493 break;
494 }
495
496 // NOTE loco::DataType::FLOAT16 is added but we do not export this type
497 // as backends currently don't support this type.
498 // currently this is supported only for "Tensor(Float16) - Dequantize"
499 // sequence so that after 'fold_dequantize' option this Tensor is
500 // converted to FLOAT32.
501
502 INTERNAL_EXN_V("Unsupported datatype", oops::to_uint32(c->dtype()));
503}
504
506encodeQuantizationParameters(FlatBufferBuilder &builder, luci::CircleQuantParam *quantparam,
507 luci::CircleMXQuantParam *mx_quantparam)
508{
509 if (quantparam == nullptr and mx_quantparam == nullptr)
510 return 0;
511
512 if (mx_quantparam)
513 {
514 if (quantparam != nullptr)
515 throw std::runtime_error("Affine quantparam can not exist with MX quantparam.");
516
517 auto mx_quantize = circle::CreateMXQuantization(builder, mx_quantparam->axis);
518
519 // Note: QuantizationDetails is not supported
520 return circle::CreateQuantizationParameters(
521 builder, 0 /* min */, 0 /* max */, 0 /* scale */, 0 /* zero_point */,
522 circle::QuantizationDetails::QuantizationDetails_MXQuantization, mx_quantize.Union(),
523 0 /* quantized_dimension */);
524 }
525
530 if (quantparam->min.size() && quantparam->max.size())
531 {
532 min = builder.CreateVector(quantparam->min);
533 max = builder.CreateVector(quantparam->max);
534 }
535 if (quantparam->scale.size() && quantparam->zerop.size())
536 {
537 scale = builder.CreateVector(quantparam->scale);
538 zero_point = builder.CreateVector(quantparam->zerop);
539 }
540 // Note: QuantizationDetails is not supported
541 return circle::CreateQuantizationParameters(builder, min, max, scale, zero_point,
542 circle::QuantizationDetails::QuantizationDetails_NONE,
543 0, quantparam->quantized_dimension);
544}
545
547encodeSparsityParameters(FlatBufferBuilder &builder, luci::SparsityParam *sparsityparam)
548{
549 if (sparsityparam == nullptr)
550 return 0;
551
552 std::vector<flatbuffers::Offset<circle::DimensionMetadata>> dim_metadata_vec;
553 auto luci_dim_metadata = sparsityparam->dim_metadata;
554 for (const auto &it : luci_dim_metadata)
555 {
556 // array_segments
557 auto circle_array_segments = to_circle_sparse_index_vector(builder, it.array_segments());
558 auto circle_array_segments_type =
559 to_circle_sparse_index_vector_type(it.array_segments().type());
560
561 // array_indices
562 auto circle_array_indices = to_circle_sparse_index_vector(builder, it.array_indices());
563 auto circle_array_indices_type = to_circle_sparse_index_vector_type(it.array_indices().type());
564 auto dim_metadata = circle::CreateDimensionMetadata(
565 builder, to_circle_dimensiontype(it.format()), it.dense_size(), circle_array_segments_type,
566 circle_array_segments, circle_array_indices_type, circle_array_indices);
567 dim_metadata_vec.emplace_back(dim_metadata);
568 }
569
570 return circle::CreateSparsityParametersDirect(builder, &sparsityparam->traversal_order,
571 &sparsityparam->block_map, &dim_metadata_vec);
572}
573
574template <loco::DataType DT> bool has_same_elements(luci::CircleConst *lhs, luci::CircleConst *rhs)
575{
576 assert(lhs->dtype() == DT);
577 assert(rhs->dtype() == DT);
578 assert(lhs->size<DT>() == rhs->size<DT>());
579
580 for (uint32_t i = 0; i < lhs->size<DT>(); ++i)
581 if (lhs->at<DT>(i) != rhs->at<DT>(i))
582 return false;
583 return true;
584}
585
586bool has_same_values(luci::CircleConst *lhs, luci::CircleConst *rhs)
587{
588 if (lhs->dtype() != rhs->dtype())
589 return false;
590
591 if (lhs->rank() != rhs->rank())
592 return false;
593
594 for (uint32_t i = 0; i < lhs->rank(); ++i)
595 if (!(lhs->dim(i) == rhs->dim(i)))
596 return false;
597
598 switch (lhs->dtype())
599 {
600 case loco::DataType::FLOAT32:
601 return has_same_elements<loco::DataType::FLOAT32>(lhs, rhs);
602
603 case loco::DataType::S4:
604 return has_same_elements<loco::DataType::S4>(lhs, rhs);
605
606 case loco::DataType::S8:
607 return has_same_elements<loco::DataType::S8>(lhs, rhs);
608
609 case loco::DataType::S16:
610 return has_same_elements<loco::DataType::S16>(lhs, rhs);
611
612 case loco::DataType::S32:
613 return has_same_elements<loco::DataType::S32>(lhs, rhs);
614
615 case loco::DataType::S64:
616 return has_same_elements<loco::DataType::S64>(lhs, rhs);
617
618 case loco::DataType::U4:
619 return has_same_elements<loco::DataType::U4>(lhs, rhs);
620
621 case loco::DataType::U8:
622 return has_same_elements<loco::DataType::U8>(lhs, rhs);
623
624 case loco::DataType::BOOL:
625 return has_same_elements<loco::DataType::BOOL>(lhs, rhs);
626
627 default:
628 break;
629 }
630
631 return false;
632}
633
634uint32_t get_buffer_id(FlatBufferBuilder &builder, SerializedModelData &md, luci::CircleConst *node)
635{
636 if (node != nullptr)
637 {
638 // When buffer with same values is found, use the buffer id.
639 for (auto key_value : md._cached_buffer_id)
640 {
641 if (has_same_values(key_value.first, node))
642 return key_value.second;
643 }
644
645 // When buffer with same values is not found, generate new buffer
646 auto buffer = encodeOpBuffer(builder, md, node);
647
648 auto buffer_id = static_cast<uint32_t>(md._buffers.size());
649 md._buffers.push_back(buffer);
650
651 // Cache the newly generated buffer id
652 md._cached_buffer_id.insert({node, buffer_id});
653
654 return buffer_id;
655 }
656 else
657 {
658 // When there is no CircleConst, there is nothing to cache.
659 // So return new buffer id.
660 auto buffer = encodeOpBuffer(builder);
661
662 auto buffer_id = static_cast<uint32_t>(md._buffers.size());
663 md._buffers.push_back(buffer);
664
665 return buffer_id;
666 }
667}
668
669void exportOpDefinedTensor(const CircleTensorInfo &info, FlatBufferBuilder &builder,
671{
672 // Create and register output tensor shape
674 flatbuffers::Offset<Vector<int32_t>> shape_signature_offset;
675 if (info.shape_status() == ShapeStatus::VALID)
676 {
677 shape_offset = encodeShape(builder, info.shape());
678 shape_signature_offset = encodeShapeSignature(builder, info.shape());
679 }
680
681 auto quantparam = encodeQuantizationParameters(builder, info.quantparam(), info.mx_quantparam());
682
683 auto sparsityparam = encodeSparsityParameters(builder, info.sparsityparam());
684
685 auto buffer_id = get_buffer_id(builder, md, info.content());
686
687 auto name_offset = builder.CreateString(info.name());
688
689 auto is_variable = info.is_variable();
690
691 auto tensor_offset = CreateTensor(builder, shape_offset, info.dtype(), buffer_id, name_offset,
692 quantparam, is_variable, sparsityparam, shape_signature_offset);
693 gd._tensors.push_back(tensor_offset);
694}
695
696} // namespace
697
698namespace luci
699{
700
702{
703 md.clear();
704
705 // add one empty buffer
706 // note: this follows TFLite
707 // note: there's a comment in tflite fbs file
708 // - Note the 0th entry of this array must be an empty buffer (sentinel).
709 // - This is a convention so that tensors without a buffer can provide 0 as
710 // - their buffer.
711 md._empty_buffer = encodeOpBuffer(builder);
712 md._buffers.push_back(md._empty_buffer);
713}
714
717{
718 CircleTensorContext tensor_ctx;
719
720 // NOTE There may exist dangle CircleInput that is not visited with postorder_traversal()
721 // All dangle CircleOutput should be visited by postorder_traversal()
722 auto nodes = g->nodes();
723 for (uint32_t n = 0; n < nodes->size(); ++n)
724 {
725 auto node = dynamic_cast<luci::CircleInput *>(nodes->at(n));
726 if (node != nullptr)
727 allocateCircleTensor(node, tensor_ctx);
728 }
729
731 {
732 CircleNode *circle_node = loco::must_cast<luci::CircleNode *>(node);
733 if (dynamic_cast<const luci::CircleInput *>(circle_node) != nullptr)
734 continue;
735 allocateCircleTensor(circle_node, tensor_ctx);
736 }
737
738 for (const auto &tensor_info : tensor_ctx)
739 {
740 exportOpDefinedTensor(tensor_info, builder, md, gd);
741 }
742}
743
745{
746 auto nodes = g->nodes();
747 for (uint32_t n = 0; n < nodes->size(); ++n)
748 {
749 auto node = loco::must_cast<luci::CircleNode *>(nodes->at(n));
750 clear_tensor_index(node);
751 }
752}
753
754} // namespace luci
#define INTERNAL_EXN_V(msg, val)
@ brief throw internal exception with message and value
Definition InternalExn.h:28
#define LOGGER(name)
Definition Log.h:65
#define INFO(name)
Definition Log.h:68
Helper class to hold data needed in creation of a FlatBuffer. To serialize data, you typically call o...
Offset< String > CreateString(const char *str, size_t len)
Store a string in the buffer, which can contain any binary data.
Offset< Vector< T > > CreateVector(const T *v, size_t len)
Serialize an array into a FlatBuffer vector.
A neural network graph.
Definition Graph.h:161
Logical unit of computation.
Definition Node.h:54
BIDIRECTIONAL_SEQUENCE_LSTM in Circle.
Virtual CIRCLEBIDIRECTIONAL_SEQUENCE_LSTM_OUT in Circle.
Class to build tensor data.
Definition CircleConst.h:35
const loco::DataTypeImpl< DT >::Type & at(uint32_t n) const
uint32_t size(void) const
CUSTOM in Circle.
Virtual CIRCLECUSTOMOUT in Circle.
IF in Circle.
Definition CircleIf.h:34
Virtual CIRCLEIFOUT in Circle.
Definition CircleIfOut.h:32
CircleNode used for Input of the Graph.
Definition CircleInput.h:36
NON_MAX_SUPPRESSION_V4 in Circle.
Virtual NONMAXSUPPRESSIONV4OUT in Circle.
NON_MAX_SUPPRESSION_V5 in Circle.
Virtual NONMAXSUPPRESSIONV5OUT in Circle.
CircleOutputExclude is used to specifying not exported nodes.
CircleNode for Output of the Graph.
SPLIT in Circle.
Definition CircleSplit.h:32
Virtual CIRCLESPLITOUT in Circle.
SPLIT_V in Circle.
Virtual CIRCLESPLITVOUT in Circle.
TOPK_V2 in Circle.
Virtual CIRCLETOPKV2OUT in Circle.
Unique in Circle.
Virtual CIRCLEUNIQUEOUT in Circle.
UNPACK in Circle.
Virtual CIRCLEUNPACKOUT in Circle.
Virtual CircleVariable in Circle for 'variable' Tensor.
WHILE in Circle.
Definition CircleWhile.h:34
Virtual CIRCLEWHILEOUT in Circle.
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
volatile const char info[]
void exportOpDefinedTensor(const TFLTensorInfo &info, FlatBufferBuilder &builder, SerializedModelData &gd)
const T * data(const std::vector< T, Alloc > &v)
std::vector< loco::Node * > postorder_traversal(const std::vector< loco::Node * > &roots)
Generate postorder traversal sequence starting from "roots".
Definition Algorithm.cpp:53
std::set< Node * > succs(const Node *node)
Enumerate all the successors of a given node.
Definition Node.cpp:46
std::vector< Node * > output_nodes(Graph *)
Definition Graph.cpp:101
flatbuffers::Offset< void > to_circle_sparse_index_vector(flatbuffers::FlatBufferBuilder &fb, const SparseIndexVector &sparse_idx_vec)
bool check_size_limit(const flatbuffers::FlatBufferBuilder &fb, const uint64_t data_size)
void set_tensor_index(loco::Node *node, const CircleTensorIndex &tensor_id)
ShapeDescription to_shape_description(const luci::CircleNode *node)
circle::DimensionType to_circle_dimensiontype(luci::DimensionType type)
const char * tensor_name(const circle::Tensor *tensor)
circle::SparseIndexVector to_circle_sparse_index_vector_type(luci::SparseIndexVectorType type)
int32_t CircleTensorIndex
circle::TensorType to_circle_tensortype(loco::DataType type)
void exportOpDefinedTensors(loco::Graph *g, FlatBufferBuilder &builder, SerializedModelData &md, SerializedGraphData &gd)
create Tensors corresponding to results of all nodes in graph
void clear_tensor_index(loco::Node *node)
void prepareModelData(FlatBufferBuilder &builder, SerializedModelData &md)
one time preparation for SerializedModelData
void clearExportInfo(loco::Graph *g)
clear temporary export information annotated to graph nodes
ShapeStatus
ShapeStatus is to remember circle node shape status.
ShapeIterator end(const Shape &s)
uint32_t to_uint32(T a)
Definition InternalExn.h:33
name
Definition setup.py:158
int32_t size[5]
Definition Slice.cpp:35
int32_t begin[5]
Definition Slice.cpp:33
C++ scalar type corresponding to each DataType.
CircleQuantParam * quantparam(void) const
SparsityParam * sparsityparam(void) const
NodeName name(void) const
CircleMXQuantParam * mx_quantparam(void) const
ShapeStatus shape_status(void) const
virtual T visit(CircleNode *)
Default fallback.
std::vector< float > scale
std::vector< float > min
std::vector< float > max
std::vector< int64_t > zerop
std::vector< flatbuffers::Offset< circle::Tensor > > _tensors
std::map< luci::CircleConst *, uint32_t > _cached_buffer_id
flatbuffers::Offset< circle::Buffer > _empty_buffer
std::vector< flatbuffers::Offset< circle::Buffer > > _buffers
std::vector< uint8_t > BufferData
std::vector< int32_t > _dims
std::vector< DimMetaData > dim_metadata
std::vector< int32_t > block_map
std::vector< int32_t > traversal_order