46 CircleTensorInfo() =
default;
49 void name(
const std::string &name) { _name =
name; }
50 const std::string &
name(
void)
const {
return _name; }
53 const circle::TensorType &
dtype(
void)
const {
return _dtype; }
54 void dtype(
const circle::TensorType &dtype) { _dtype =
dtype; }
75 bool is_variable(
void)
const {
return _is_variable; }
76 void is_variable(
bool v) { _is_variable = v; }
81 circle::TensorType _dtype{circle::TensorType_FLOAT32};
90 bool _is_variable =
false;
93class CircleTensorContext
96 CircleTensorContext() =
default;
99 void emplace_back(CircleTensorInfo &ti)
101 assert(_names.find(ti.name()) == _names.end());
102 _tis.emplace_back(ti);
103 _names.insert(ti.name());
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(); }
110 bool exist(
const std::string &name)
const {
return _names.find(name) != _names.end(); }
113 std::vector<CircleTensorInfo> _tis;
114 std::set<std::string> _names;
128void allocateCircleTensorInfo(
CircleNode *node, CircleTensorContext &ctx)
145 INFO(l) <<
"[luci] Tensor for " <<
tensor_name <<
": " << tensor_index << std::endl;
147 CircleTensorInfo tensor_info;
164 ctx.emplace_back(tensor_info);
170 MultiOutputDetector(CircleTensorContext &ctx) : _ctx(ctx) {}
176 assert(outs.size() == count);
178 for (
auto out : outs)
180 auto circle_out = loco::must_cast<luci::CircleNode *>(out);
181 allocateCircleTensorInfo(circle_out, _ctx);
201 if (node->merge_outputs())
203 store_outputs(node, 1);
207 store_outputs(node, 2);
214 store_outputs(node, node->numOutputs());
220 store_outputs(node, node->output_count());
226 store_outputs(node, 2);
232 store_outputs(node, 3);
238 store_outputs(node, uint32_t(node->num_split()));
244 store_outputs(node, uint32_t(node->num_split()));
250 store_outputs(node, 2);
256 store_outputs(node, node->num());
262 store_outputs(node, 2);
268 store_outputs(node, node->output_count());
276 CircleTensorContext &_ctx;
279void allocateCircleTensor(
CircleNode *node, CircleTensorContext &ctx)
282 throw std::runtime_error(
"allocateCIrcleTensor Failed : node is nullptr");
288 return circle_node->accept(&d);
303 MultiOutputDetector d(ctx);
304 if (circle_node->accept(&d))
308 allocateCircleTensorInfo(node, ctx);
319 assert(shape.
_rank_known &&
"unknown number of dimensions is not supported");
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);
332 assert(shape.
_rank_known &&
"unknown number of dimensions is not supported");
335 for (uint32_t i = 0; i < shape.
_dims.size(); ++i)
336 if (shape.
_dims.at(i) == -1)
344 return CreateBuffer(builder);
347template <
typename NodeT>
351 return CreateBuffer(builder);
354template <loco::DataType DT>
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)
365 raw_data.push_back(c->
at<DT>(i));
367 const size_t raw_size =
size *
sizeof(NativeType);
373 buffer_data.resize(raw_size);
374 std::memcpy(buffer_data.data(), raw_data.data(), raw_size);
376 int32_t buffer_index = md.
_buffers.size();
380 return circle::CreateBuffer(builder, 0 , 1 , 1 );
388 auto array_offset = builder.
CreateVector(
reinterpret_cast<uint8_t *
>(raw_data.data()), raw_size);
389 return CreateBuffer(builder, array_offset);
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)
401 auto &value = c->
at<loco::DataType::STRING>(i);
402 raw_size += value.length();
409 std::vector<uint8_t> raw_data;
410 raw_data.reserve(raw_size);
412 auto *i32d =
reinterpret_cast<int32_t *
>(raw_data.data());
413 int32_t start =
sizeof(int32_t) * (count + 2);
415 std::vector<int32_t> offsets;
419 offsets.push_back(start);
420 for (uint32_t i = 0; i < count; ++i)
422 auto &value = c->
at<loco::DataType::STRING>(i);
425 offsets.push_back(
offset);
428 auto *
data =
reinterpret_cast<uint8_t *
>(i32d);
429 for (uint32_t i = 0; i < count; ++i)
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);
437 auto array_offset = builder.
CreateVector(
reinterpret_cast<uint8_t *
>(raw_data.data()), raw_size);
438 return CreateBuffer(builder, array_offset);
441template <loco::DataType DT>
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);
449 for (uint32_t i = 0; i < raw_size; ++i)
451 uint32_t sidx = i * 2;
452 uint8_t
data =
static_cast<uint8_t
>(c->
at<DT>(sidx));
453 raw_data[i] =
data & 0x0f;
457 data =
static_cast<uint8_t
>(c->
at<DT>(sidx));
458 raw_data[i] |=
data << 4;
462 auto array_offset = builder.
CreateVector(raw_data.data(), raw_size);
463 return CreateBuffer(builder, array_offset);
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);
509 if (quantparam ==
nullptr and mx_quantparam ==
nullptr)
514 if (quantparam !=
nullptr)
515 throw std::runtime_error(
"Affine quantparam can not exist with MX quantparam.");
517 auto mx_quantize = circle::CreateMXQuantization(builder, mx_quantparam->
axis);
520 return circle::CreateQuantizationParameters(
521 builder, 0 , 0 , 0 , 0 ,
522 circle::QuantizationDetails::QuantizationDetails_MXQuantization, mx_quantize.Union(),
530 if (quantparam->
min.size() && quantparam->
max.size())
535 if (quantparam->
scale.size() && quantparam->
zerop.size())
541 return circle::CreateQuantizationParameters(builder, min, max, scale, zero_point,
542 circle::QuantizationDetails::QuantizationDetails_NONE,
549 if (sparsityparam ==
nullptr)
552 std::vector<flatbuffers::Offset<circle::DimensionMetadata>> dim_metadata_vec;
554 for (
const auto &it : luci_dim_metadata)
558 auto circle_array_segments_type =
564 auto dim_metadata = circle::CreateDimensionMetadata(
566 circle_array_segments, circle_array_indices_type, circle_array_indices);
567 dim_metadata_vec.emplace_back(dim_metadata);
570 return circle::CreateSparsityParametersDirect(builder, &sparsityparam->
traversal_order,
571 &sparsityparam->
block_map, &dim_metadata_vec);
576 assert(lhs->dtype() == DT);
577 assert(rhs->dtype() == DT);
578 assert(lhs->
size<DT>() == rhs->
size<DT>());
580 for (uint32_t i = 0; i < lhs->
size<DT>(); ++i)
581 if (lhs->
at<DT>(i) != rhs->
at<DT>(i))
588 if (lhs->dtype() != rhs->dtype())
591 if (lhs->rank() != rhs->rank())
594 for (uint32_t i = 0; i < lhs->rank(); ++i)
595 if (!(lhs->dim(i) == rhs->dim(i)))
598 switch (lhs->dtype())
600 case loco::DataType::FLOAT32:
601 return has_same_elements<loco::DataType::FLOAT32>(lhs, rhs);
603 case loco::DataType::S4:
604 return has_same_elements<loco::DataType::S4>(lhs, rhs);
606 case loco::DataType::S8:
607 return has_same_elements<loco::DataType::S8>(lhs, rhs);
609 case loco::DataType::S16:
610 return has_same_elements<loco::DataType::S16>(lhs, rhs);
612 case loco::DataType::S32:
613 return has_same_elements<loco::DataType::S32>(lhs, rhs);
615 case loco::DataType::S64:
616 return has_same_elements<loco::DataType::S64>(lhs, rhs);
618 case loco::DataType::U4:
619 return has_same_elements<loco::DataType::U4>(lhs, rhs);
621 case loco::DataType::U8:
622 return has_same_elements<loco::DataType::U8>(lhs, rhs);
624 case loco::DataType::BOOL:
625 return has_same_elements<loco::DataType::BOOL>(lhs, rhs);
639 for (
auto key_value : md._cached_buffer_id)
641 if (has_same_values(key_value.first, node))
642 return key_value.second;
646 auto buffer = encodeOpBuffer(builder, md, node);
648 auto buffer_id =
static_cast<uint32_t
>(md.
_buffers.size());
660 auto buffer = encodeOpBuffer(builder);
662 auto buffer_id =
static_cast<uint32_t
>(md.
_buffers.size());
675 if (
info.shape_status() == ShapeStatus::VALID)
677 shape_offset = encodeShape(builder,
info.shape());
678 shape_signature_offset = encodeShapeSignature(builder,
info.shape());
681 auto quantparam = encodeQuantizationParameters(builder,
info.quantparam(),
info.mx_quantparam());
683 auto sparsityparam = encodeSparsityParameters(builder,
info.sparsityparam());
685 auto buffer_id = get_buffer_id(builder, md,
info.content());
689 auto is_variable =
info.is_variable();
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);
718 CircleTensorContext tensor_ctx;
722 auto nodes = g->nodes();
723 for (uint32_t n = 0; n < nodes->size(); ++n)
727 allocateCircleTensor(node, tensor_ctx);
732 CircleNode *circle_node = loco::must_cast<luci::CircleNode *>(node);
735 allocateCircleTensor(circle_node, tensor_ctx);
738 for (
const auto &tensor_info : tensor_ctx)
740 exportOpDefinedTensor(tensor_info, builder, md, gd);
746 auto nodes = g->nodes();
747 for (uint32_t n = 0; n < nodes->size(); ++n)
749 auto node = loco::must_cast<luci::CircleNode *>(nodes->at(n));
#define INTERNAL_EXN_V(msg, val)
@ brief throw internal exception with message and value
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.
Logical unit of computation.
BIDIRECTIONAL_SEQUENCE_LSTM in Circle.
Virtual CIRCLEBIDIRECTIONAL_SEQUENCE_LSTM_OUT in Circle.
Class to build tensor data.
const loco::DataTypeImpl< DT >::Type & at(uint32_t n) const
uint32_t size(void) const
Virtual CIRCLECUSTOMOUT in Circle.
Virtual CIRCLEIFOUT in Circle.
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.
Virtual CIRCLESPLITOUT in Circle.
Virtual CIRCLESPLITVOUT in Circle.
Virtual CIRCLETOPKV2OUT in Circle.
Virtual CIRCLEUNIQUEOUT in Circle.
Virtual CIRCLEUNPACKOUT in Circle.
Virtual CircleVariable in Circle for 'variable' Tensor.
Virtual CIRCLEWHILEOUT in Circle.
__global uchar * offset(const Image *img, int x, int y)
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".
std::set< Node * > succs(const Node *node)
Enumerate all the successors of a given node.
std::vector< Node * > output_nodes(Graph *)
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)
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
int32_t quantized_dimension
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
MapBufferData _buffer_data_map
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