2 * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
3 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 #ifndef __BASE_LOADER_BASE_LOADER_H__
19 #define __BASE_LOADER_BASE_LOADER_H__
23 #include "ir/Operations.Include.h"
25 #include "flatbuffers/flexbuffers.h"
35 #include <util/logging.h>
42 template <typename LoaderDomain> class BaseLoader
45 using Verifier = typename LoaderDomain::Verifier;
46 using ActivationFunctionType = typename LoaderDomain::ActivationFunctionType;
47 using Buffer = typename LoaderDomain::Buffer;
48 using BuiltinOperator = typename LoaderDomain::BuiltinOperator;
49 using CustomOptionsFormat = typename LoaderDomain::CustomOptionsFormat;
50 using Model = typename LoaderDomain::Model;
51 using Operator = typename LoaderDomain::Operator;
52 using Padding = typename LoaderDomain::Padding;
53 using Pool2DOptions = typename LoaderDomain::Pool2DOptions;
54 using SubGraph = typename LoaderDomain::SubGraph;
55 using Tensor = typename LoaderDomain::Tensor;
56 using TensorType = typename LoaderDomain::TensorType;
57 using DimensionType = typename LoaderDomain::DimensionType;
58 using SparseIndexVector = typename LoaderDomain::SparseIndexVector;
61 bool isOptionalInputTensor(std::int32_t idx) { return idx == -1; }
62 virtual bool allowOptionalInputTensor(BuiltinOperator) = 0;
66 * @brief Construct a new Loader object
68 * @param graph reference on subgraphs
70 explicit BaseLoader(std::unique_ptr<ir::Subgraphs> &subgs)
71 : _base{nullptr}, _pagesize(getpagesize()), _fd(-1), _subgraphs(subgs), _model{nullptr}
73 _use_mmaped_data = util::getConfigBool(util::config::USE_MMAPED_DATA);
77 * @brief Load a model from file
81 void loadFromFile(const char *file_path);
83 * @brief Load a model from a buffer
85 * @param buffer buffer pointer
86 * @param size buffer size
88 void loadFromBuffer(uint8_t *buffer, size_t size);
91 ~BaseLoader() = default;
95 ir::Activation convertActivation(ActivationFunctionType type);
96 ir::DataType tensorTypeToDataType(TensorType type);
97 ir::OperandIndex tensorIdxToOperandIdx(int32_t tensorIdx);
99 // Create operands form tflite::Tensor
100 ir::OperandIndex loadOperand(const Tensor *tensor, ir::Graph &subg);
101 void loadSparsity(const Tensor *tensor, const ir::Shape &shape, ir::TypeInfo &typeInfo);
102 void loadOperationIO(const Operator *op, ir::OperandIndexSequence &inputs,
103 ir::OperandIndexSequence &outputs);
104 // Create operations from Operator
105 void loadOperation(const Operator *op, ir::Graph &subg);
106 // Load Strides and Paddings from options to param
107 template <typename Param, typename OptionsType>
108 void loadStridesAndPaddings(Param ¶m, const OptionsType *options);
110 template <typename Param> void loadPool2DOptions(Param ¶m, const Pool2DOptions *options);
113 virtual std::unique_ptr<ir::Graph> loadSubgraph(const SubGraph *subg) = 0;
115 template <typename OpIR, typename... Args>
116 const OpIR *loadOperationTo(const Operator *op, ir::Graph &subg, Args &&... args);
118 void loadAddV2(const Operator *op, ir::Graph &subg);
119 void loadArgMinMax(const Operator *op, ir::Graph &subg, bool is_argmax);
120 void loadBatchMatMul(const Operator *op, ir::Graph &subg);
121 void loadBinaryArithmetic(const Operator *op, ir::Graph &subg,
122 ir::operation::BinaryArithmetic::ArithmeticType op_type);
123 void loadComparison(const Operator *op, ir::Graph &subg);
124 void loadConcatenation(const Operator *op, ir::Graph &subg);
125 void loadConv2D(const Operator *op, ir::Graph &subg);
126 void loadCustom(const Operator *op, ir::Graph &subg);
127 void loadDepthToSpace(const Operator *op, ir::Graph &subg);
128 void loadDepthwiseConv2D(const Operator *op, ir::Graph &subg);
129 void loadEinsum(const Operator *op, ir::Graph &subg);
130 void loadElementwiseActivation(const Operator *op, ir::Graph &subg,
131 ir::operation::ElementwiseActivation::Type op_type,
132 float alpha = 0.f, float beta = 0.f);
133 void loadElementwiseBinary(const Operator *op, ir::Graph &subg,
134 ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type);
135 void loadElementwiseUnary(const Operator *op, ir::Graph &subg,
136 ir::operation::ElementwiseUnary::Type op_type);
137 void loadFC(const Operator *op, ir::Graph &subg);
138 void loadFusedBatchNorm(const Operator *op, ir::Graph &subg);
139 void loadGather(const Operator *op, ir::Graph &subg);
140 void loadIf(const Operator *op, ir::Graph &subg);
141 void loadLeakyRelu(const Operator *op, ir::Graph &subg);
142 void loadLogSoftmax(const Operator *op, ir::Graph &subg);
143 void loadOneHot(const Operator *op, ir::Graph &subg);
144 void loadPack(const Operator *op, ir::Graph &subg);
145 void loadPool2D(const Operator *op, ir::Graph &subg, ir::operation::Pool2D::PoolType op_type);
146 void loadReduce(const Operator *op, ir::Graph &subg,
147 ir::operation::Reduce::ReduceType reduce_type);
148 void loadReduceAll(const Operator *op, ir::Graph &subg);
149 void loadReshape(const Operator *op, ir::Graph &subg);
150 void loadResizeBilinear(const Operator *op, ir::Graph &subg);
151 void loadResizeNearestNeighbor(const Operator *op, ir::Graph &subg);
152 void loadSoftmax(const Operator *op, ir::Graph &subg);
153 void loadSpaceToDepth(const Operator *op, ir::Graph &subg);
154 void loadSplit(const Operator *op, ir::Graph &subg);
155 void loadSplitV(const Operator *op, ir::Graph &subg);
156 void loadSqueeze(const Operator *op, ir::Graph &subg);
157 void loadStridedSlice(const Operator *op, ir::Graph &subg);
158 void loadTransposeConv(const Operator *op, ir::Graph &subg);
159 void loadUnidirectionalSequenceLSTM(const Operator *op, ir::Graph &subg);
160 void loadUnpack(const Operator *op, ir::Graph &subg);
161 void loadWhile(const Operator *op, ir::Graph &subg);
163 void verifySubgraphIndex(int subg_index)
165 const auto num_subgraphs = _model->subgraphs()->size();
166 if (subg_index < 0 || subg_index >= static_cast<int32_t>(num_subgraphs))
167 throw std::runtime_error{std::string{"Invalid subgraph index - "} +
168 std::to_string(subg_index)};
172 // Base address for mapped region for loading (if needed)
176 // loaded file description
178 // Reference on loadable subgraphs
179 std::unique_ptr<ir::Subgraphs> &_subgraphs;
181 // Maps Tensor indices to onert Operands.
182 std::vector<ir::OperandIndex> _tensor_to_operand;
183 std::unordered_map<ir::OperandIndex, std::string> _tensor_names;
185 std::unique_ptr<Verifier> _verifier;
186 // Boolean flag to use MMAPED_DATA
187 bool _use_mmaped_data = false;
190 template <typename LoaderDomain>
191 void BaseLoader<LoaderDomain>::BaseLoader::loadFromFile(const char *file_path)
193 _fd = open(file_path, O_RDONLY);
196 throw std::runtime_error("Failed to open file " + std::string(file_path));
199 struct stat file_stat;
200 if (fstat(_fd, &file_stat) != 0)
202 throw std::runtime_error("Fstat failed or file " + std::string(file_path) +
203 " is not a regular file");
205 int size = file_stat.st_size;
207 // Map model file into memory region
208 _base = static_cast<uint8_t *>(mmap(NULL, size, PROT_READ, MAP_PRIVATE, _fd, 0));
209 if (_base == MAP_FAILED)
212 throw std::runtime_error("mmap failed - " + std::string(strerror(errno)));
215 _verifier = std::make_unique<Verifier>(reinterpret_cast<const std::uint8_t *>(_base), size);
223 template <typename LoaderDomain>
224 void BaseLoader<LoaderDomain>::BaseLoader::loadFromBuffer(uint8_t *buffer, size_t size)
227 _verifier = std::make_unique<Verifier>(reinterpret_cast<const std::uint8_t *>(_base), size);
231 template <typename LoaderDomain>
233 BaseLoader<LoaderDomain>::BaseLoader::convertActivation(const ActivationFunctionType type)
237 case ActivationFunctionType::ActivationFunctionType_NONE:
238 return ir::Activation::NONE;
239 case ActivationFunctionType::ActivationFunctionType_RELU:
240 return ir::Activation::RELU;
241 case ActivationFunctionType::ActivationFunctionType_RELU_N1_TO_1:
242 return ir::Activation::RELU1;
243 case ActivationFunctionType::ActivationFunctionType_RELU6:
244 return ir::Activation::RELU6;
245 case ActivationFunctionType::ActivationFunctionType_TANH:
246 return ir::Activation::TANH;
248 throw std::runtime_error(std::string("Unsupported or invalid activation type: ") +
249 std::to_string(static_cast<int>(type)));
253 template <typename LoaderDomain>
254 ir::DataType BaseLoader<LoaderDomain>::BaseLoader::tensorTypeToDataType(const TensorType type)
258 case TensorType::TensorType_FLOAT32:
259 return ir::DataType::FLOAT32;
260 case TensorType::TensorType_FLOAT16:
261 return ir::DataType::FLOAT16;
262 case TensorType::TensorType_INT32:
263 return ir::DataType::INT32;
264 case TensorType::TensorType_UINT8:
265 return ir::DataType::QUANT_UINT8_ASYMM;
266 case TensorType::TensorType_INT64:
267 return ir::DataType::INT64;
268 // case TensorType::TensorType_STRING:
269 case TensorType::TensorType_BOOL:
270 return ir::DataType::BOOL8;
271 case TensorType::TensorType_INT16:
272 return ir::DataType::QUANT_INT16_ASYMM;
273 // case TensorType::TensorType_COMPLEX64
274 case TensorType::TensorType_INT8:
275 return ir::DataType::QUANT_INT8_ASYMM;
276 // case TensorType::TensorType_FLOAT64
278 throw std::runtime_error(
279 std::string("Unsupported tensor type: ").append(EnumNameTensorType(type)));
283 template <typename LoaderDomain>
284 ir::OperandIndex BaseLoader<LoaderDomain>::BaseLoader::tensorIdxToOperandIdx(int32_t tensorIdx)
286 return isOptionalInputTensor(tensorIdx) ? ir::OperandIndex() : _tensor_to_operand[tensorIdx];
289 /* Copy is copied from tensorflow lite */
290 template <typename T> bool Copy(const T *data_ptr, std::vector<uint16_t> &arr)
292 if (data_ptr->values() == nullptr)
297 int size = data_ptr->values()->size();
299 for (int i = 0; i < size; i++)
301 arr.emplace_back(static_cast<uint16_t>(data_ptr->values()->Get(i)));
306 template <typename LoaderDomain>
307 ir::OperandIndex BaseLoader<LoaderDomain>::loadOperand(const Tensor *tensor, ir::Graph &subg)
311 const auto *tensor_shape = tensor->shape();
312 if (tensor_shape != nullptr)
314 for (const auto &dim : *tensor_shape)
320 // Note for tensor->shape_signature()
321 // We don't handle shape signature
323 // If shape_signature[k] == -1, we will use tensor->shape()[k] == 1
324 // If app wants to change the input shape, call nnfw_apply_input_tensorinfo() can
328 ir::DataType data_type = tensorTypeToDataType(tensor->type());
330 auto q_params = tensor->quantization();
333 if (q_params != nullptr)
335 if (q_params->scale())
337 if (q_params->scale()->size() != 1)
339 throw std::runtime_error("Only 1 scale for a tensor is supported.");
341 scale = q_params->scale()->Get(0);
344 if (q_params->zero_point())
346 if (q_params->zero_point()->size() != 1)
348 throw std::runtime_error("Only 1 zero_point value for a tensor is supported.");
350 zero_point = q_params->zero_point()->Get(0);
351 // zero_point is long while TypeInfo.zero_point is defined as int32_t.
352 assert(zero_point >= std::numeric_limits<int32_t>::min());
353 assert(zero_point <= std::numeric_limits<int32_t>::max());
355 auto details = q_params->details_as_CustomQuantization();
356 if (details != nullptr)
357 throw std::runtime_error("Custom Quantization is not supported");
360 ir::TypeInfo type_info(data_type, scale, zero_point);
362 loadSparsity(tensor, shape, type_info);
365 const auto operand_index = subg.addOperand(shape, type_info);
367 // Constant tensors are indicated by non-empty data.
368 const auto *data = _model->buffers()->Get(tensor->buffer())->data();
371 using std::ptrdiff_t;
372 std::unique_ptr<ir::Data> data_obj;
373 if (_fd == -1) // Model is from memory
375 data_obj = std::make_unique<ir::ExternalData>(data->data(), data->size());
377 else // Model is loaded(mmap'd) from a file
379 size_t data_size = data->size();
380 ptrdiff_t unaligned_offset_start = data->data() - _base;
381 ptrdiff_t offset_end = unaligned_offset_start + data_size;
383 // Calculated aligned offset from base address of mapped region
384 // munmap accepts memory address which is a multiple of the pagesize
385 ptrdiff_t aligned_offset_start = (unaligned_offset_start / _pagesize) * _pagesize;
386 size_t mmap_size = offset_end - aligned_offset_start;
388 if (_use_mmaped_data)
390 data_obj = std::make_unique<ir::MMapedData>(_fd, aligned_offset_start, mmap_size,
391 unaligned_offset_start, data_size);
395 size_t offset = unaligned_offset_start - aligned_offset_start;
396 uint8_t *mmap_base = static_cast<uint8_t *>(
397 mmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, _fd, aligned_offset_start));
398 data_obj = std::make_unique<ir::CachedData>(mmap_base + offset, data_size);
399 munmap(mmap_base, mmap_size);
402 subg.setOperandValue(operand_index, std::move(data_obj));
405 _tensor_names.emplace(operand_index, tensor->name()->str());
408 if (tensor->is_variable())
411 throw std::runtime_error("Variable tensor with buffer is not supported!");
413 subg.operands().at(operand_index).info().setAsVariable();
416 return operand_index;
419 template <typename LoaderDomain>
420 void BaseLoader<LoaderDomain>::loadSparsity(const Tensor *tensor, const ir::Shape &shape,
421 ir::TypeInfo &typeInfo)
423 auto src_sparsity = tensor->sparsity();
424 if (src_sparsity != nullptr)
426 std::vector<uint16_t> w1_segments;
427 std::vector<uint16_t> w1_indices;
428 // check traversal_order
429 if (src_sparsity->traversal_order())
431 const int traversal_order_size = src_sparsity->traversal_order()->size();
432 for (int i = 0; i < traversal_order_size; ++i)
434 if (i != src_sparsity->traversal_order()->Get(i))
435 throw std::runtime_error("traversal_order [0, 1, ..., n-1] is only supported.");
440 if (src_sparsity->block_map())
442 block_rank = src_sparsity->block_map()->size();
443 for (int i = 0; i < block_rank; ++i)
445 if (i != src_sparsity->block_map()->Get(i))
446 throw std::runtime_error("block_map [0, 1, ..., n-1] is only supported.");
450 const int dim_metadata_size = src_sparsity->dim_metadata()->size();
451 auto dense_rank = shape.rank();
452 if (dense_rank + block_rank != dim_metadata_size)
453 throw std::runtime_error("sparsity dim_metadata length is wrong.");
454 bool random_sparsity = dim_metadata_size == 2 && block_rank == 0;
455 bool block2D_sparsity = dim_metadata_size == 4 && block_rank == 2;
456 if (dim_metadata_size != !random_sparsity && !block2D_sparsity)
457 throw std::runtime_error(
458 "sparsity is supported only for 2D tensor with random or 16x1 block sparsity.");
460 const auto *src_metadata = src_sparsity->dim_metadata()->Get(0);
461 if (src_metadata->format() != DimensionType::DimensionType_DENSE)
462 throw std::runtime_error("sparse tensor dim[0] is not DENSE");
463 src_metadata = src_sparsity->dim_metadata()->Get(1);
464 if (src_metadata->format() != DimensionType::DimensionType_SPARSE_CSR)
465 throw std::runtime_error("sparse tensor dim[0] is not SPARSE_CSR");
466 auto ParseSparseIndexVector = [src_metadata, &w1_segments, &w1_indices]() {
467 if (src_metadata->array_segments() == nullptr || src_metadata->array_indices() == nullptr)
470 switch (src_metadata->array_segments_type())
472 case SparseIndexVector::SparseIndexVector_Int32Vector:
473 status = Copy(src_metadata->array_segments_as_Int32Vector(), w1_segments);
475 case SparseIndexVector::SparseIndexVector_Uint16Vector:
476 status = Copy(src_metadata->array_segments_as_Uint16Vector(), w1_segments);
478 case SparseIndexVector::SparseIndexVector_Uint8Vector:
479 status = Copy(src_metadata->array_segments_as_Uint8Vector(), w1_segments);
486 switch (src_metadata->array_indices_type())
488 case SparseIndexVector::SparseIndexVector_Int32Vector:
489 return Copy(src_metadata->array_indices_as_Int32Vector(), w1_indices);
490 case SparseIndexVector::SparseIndexVector_Uint16Vector:
491 return Copy(src_metadata->array_indices_as_Uint16Vector(), w1_indices);
492 case SparseIndexVector::SparseIndexVector_Uint8Vector:
493 return Copy(src_metadata->array_indices_as_Uint8Vector(), w1_indices);
499 if (ParseSparseIndexVector() == false)
500 throw std::runtime_error("Error during parsing sparsity index information");
502 std::vector<int32_t> block_size;
503 for (int i = 0; i < block_rank; ++i)
505 auto block_metadata = src_sparsity->dim_metadata()->Get(dense_rank + i);
506 if (block_metadata->format() != DimensionType::DimensionType_DENSE)
507 throw std::runtime_error("block dimension must be DENSE.");
508 block_size.push_back(block_metadata->dense_size());
510 typeInfo.sparsity(std::make_shared<ir::Sparsity>(std::move(w1_segments), std::move(w1_indices),
511 std::move(block_size)));
515 template <typename LoaderDomain>
516 void BaseLoader<LoaderDomain>::loadOperationIO(const Operator *op, ir::OperandIndexSequence &inputs,
517 ir::OperandIndexSequence &outputs)
519 for (const std::int32_t idx : *op->inputs())
521 // Optional tensors are not supported yet except for FULLY_CONNECTED and BCQ_FULLY_CONNECTED
522 auto check_optional_input = [&]() {
523 auto builtin_code = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
524 if (isOptionalInputTensor(idx) && !allowOptionalInputTensor(builtin_code))
525 throw std::runtime_error(
526 std::string("loader doesn't support optional input tensor yet for ")
527 .append(EnumNameBuiltinOperator(builtin_code)));
529 check_optional_input();
530 inputs.append(tensorIdxToOperandIdx(idx));
533 for (const std::int32_t idx : *op->outputs())
535 outputs.append(tensorIdxToOperandIdx(idx));
539 template <typename LoaderDomain>
540 template <typename Param, typename OptionsType>
541 void BaseLoader<LoaderDomain>::loadStridesAndPaddings(Param ¶m, const OptionsType *options)
544 param.stride.vertical = options->stride_h();
545 param.stride.horizontal = options->stride_w();
547 switch (options->padding())
549 case Padding::Padding_SAME:
550 param.padding.type = ir::PaddingType::SAME;
552 case Padding::Padding_VALID:
553 param.padding.type = ir::PaddingType::VALID;
556 throw std::runtime_error{"Invalid padding type"};
558 // param paddings indexes unused
561 template <typename LoaderDomain>
562 template <typename Param>
563 void BaseLoader<LoaderDomain>::loadPool2DOptions(Param ¶m, const Pool2DOptions *options)
565 // Strides and Paddings
566 if (options->stride_h() <= 0 || options->stride_w() <= 0)
567 throw std::runtime_error{"Invalid stride vertical or horizontal - both must be bigger than 0"};
568 loadStridesAndPaddings(param, options);
569 // Filter width and height
571 if (options->filter_width() <= 0 || options->filter_height() <= 0)
572 throw std::runtime_error{"Invalid filter width or height - both must be bigger than 0"};
573 param.kw = options->filter_width();
574 param.kh = options->filter_height();
576 param.activation = convertActivation(options->fused_activation_function());
579 template <typename LoaderDomain>
580 template <typename OpIR, typename... Args>
581 const OpIR *BaseLoader<LoaderDomain>::loadOperationTo(const Operator *op, ir::Graph &subg,
584 static_assert(sizeof...(args) <= 1, "You can't have more than 1 arguments!");
585 ir::OperandIndexSequence inputs;
586 ir::OperandIndexSequence outputs;
588 loadOperationIO(op, inputs, outputs);
590 std::unique_ptr<OpIR> new_op(new OpIR(inputs, outputs, std::forward<Args>(args)...));
591 auto ret = new_op.get();
592 subg.addOperation(std::move(new_op));
597 template <typename LoaderDomain>
598 void BaseLoader<LoaderDomain>::loadConv2D(const Operator *op, ir::Graph &subg)
600 ir::operation::Conv2D::Param param;
601 const auto *options = op->builtin_options_as_Conv2DOptions();
602 param.activation = convertActivation(options->fused_activation_function());
603 loadStridesAndPaddings(param, options);
604 param.dilation.width_factor = options->dilation_w_factor();
605 param.dilation.height_factor = options->dilation_h_factor();
607 loadOperationTo<ir::operation::Conv2D>(op, subg, param);
610 template <typename LoaderDomain>
611 void BaseLoader<LoaderDomain>::loadDepthwiseConv2D(const Operator *op, ir::Graph &subg)
613 ir::operation::DepthwiseConv2D::Param param;
614 const auto *options = op->builtin_options_as_DepthwiseConv2DOptions();
615 param.activation = convertActivation(options->fused_activation_function());
616 loadStridesAndPaddings(param, options);
617 param.multiplier = options->depth_multiplier();
618 // Dilation h/w factor unused
619 param.dilation.width_factor = options->dilation_w_factor();
620 param.dilation.height_factor = options->dilation_h_factor();
622 loadOperationTo<ir::operation::DepthwiseConv2D>(op, subg, param);
625 template <typename LoaderDomain>
626 void BaseLoader<LoaderDomain>::loadTransposeConv(const Operator *op, ir::Graph &subg)
628 ir::operation::TransposeConv::Param param;
629 const auto *options = op->builtin_options_as_TransposeConvOptions();
630 loadStridesAndPaddings(param, options);
632 loadOperationTo<ir::operation::TransposeConv>(op, subg, param);
635 template <typename LoaderDomain>
636 void BaseLoader<LoaderDomain>::loadPool2D(const Operator *op, ir::Graph &subg,
637 ir::operation::Pool2D::PoolType op_type)
639 ir::operation::Pool2D::Param param;
640 param.op_type = op_type;
641 const auto *options = op->builtin_options_as_Pool2DOptions();
643 loadPool2DOptions(param, options);
645 loadOperationTo<ir::operation::Pool2D>(op, subg, param);
648 template <typename LoaderDomain>
649 void BaseLoader<LoaderDomain>::loadReshape(const Operator *op, ir::Graph &subg)
651 ir::operation::Reshape::Param param{};
652 const auto *options = op->builtin_options_as_ReshapeOptions();
653 if (options != nullptr)
655 const auto *new_shape = options->new_shape();
658 for (uint i = 0; i < new_shape->size(); ++i)
660 param.new_shape.push_back(new_shape->Get(i));
665 loadOperationTo<ir::operation::Reshape>(op, subg, param);
668 template <typename LoaderDomain>
669 void BaseLoader<LoaderDomain>::loadSoftmax(const Operator *op, ir::Graph &subg)
671 ir::operation::Softmax::Param param;
672 const auto *options = op->builtin_options_as_SoftmaxOptions();
674 param.beta = options->beta();
676 loadOperationTo<ir::operation::Softmax>(op, subg, param);
679 template <typename LoaderDomain>
680 void BaseLoader<LoaderDomain>::loadConcatenation(const Operator *op, ir::Graph &subg)
682 ir::operation::Concat::Param param;
683 const auto *options = op->builtin_options_as_ConcatenationOptions();
685 param.axis = options->axis();
688 loadOperationTo<ir::operation::Concat>(op, subg, param);
691 template <typename LoaderDomain>
692 void BaseLoader<LoaderDomain>::loadFC(const Operator *op, ir::Graph &subg)
694 ir::operation::FullyConnected::Param param;
695 const auto *options = op->builtin_options_as_FullyConnectedOptions();
697 param.activation = convertActivation(options->fused_activation_function());
698 param.weights_format = static_cast<ir::FullyConnectedWeightsFormat>(options->weights_format());
700 const auto fc = loadOperationTo<ir::operation::FullyConnected>(op, subg, param);
702 const auto &input_operand =
703 subg.operands().at(fc->getInputs().at(ir::operation::FullyConnected::INPUT));
704 auto &weights_operand =
705 subg.operands().at(fc->getInputs().at(ir::operation::FullyConnected::WEIGHT));
706 if (input_operand.typeInfo().type() == ir::DataType::FLOAT32 &&
707 ((weights_operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM) ||
708 weights_operand.typeInfo().type() == ir::DataType::QUANT_INT8_ASYMM))
710 weights_operand.type(ir::DataType::QUANT_INT8_SYMM);
714 template <typename LoaderDomain>
715 void BaseLoader<LoaderDomain>::loadAddV2(const Operator *op, ir::Graph &subg)
717 ir::operation::BinaryArithmetic::Param param;
718 param.arithmetic_type = ir::operation::BinaryArithmetic::ArithmeticType::ADD;
720 if (op->custom_options() == nullptr)
722 param.activation = ir::Activation::NONE;
726 size_t custom_op_data_size = op->custom_options()->size();
727 auto custom_op_data = op->custom_options()->Data();
728 auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
729 auto attr_map = data_root.AsMap();
730 const auto fused_activation_func = static_cast<typename LoaderDomain::ActivationFunctionType>(
731 attr_map["fused_activation_function"].AsInt8());
732 param.activation = convertActivation(fused_activation_func);
735 loadOperationTo<ir::operation::BinaryArithmetic>(op, subg, param);
738 template <typename LoaderDomain>
739 void BaseLoader<LoaderDomain>::loadDepthToSpace(const Operator *op, ir::Graph &subg)
741 ir::operation::DepthToSpace::Param param;
742 const auto *options = op->builtin_options_as_DepthToSpaceOptions();
743 param.block_size = options->block_size();
745 loadOperationTo<ir::operation::DepthToSpace>(op, subg, param);
748 template <typename LoaderDomain>
749 void BaseLoader<LoaderDomain>::loadBinaryArithmetic(
750 const Operator *op, ir::Graph &subg, ir::operation::BinaryArithmetic::ArithmeticType op_type)
752 ir::operation::BinaryArithmetic::Param param;
753 param.arithmetic_type = op_type;
756 case ir::operation::BinaryArithmetic::ArithmeticType::ADD:
758 const auto *add_options = op->builtin_options_as_AddOptions();
759 param.activation = convertActivation(add_options->fused_activation_function());
762 case ir::operation::BinaryArithmetic::ArithmeticType::SUB:
764 const auto *sub_options = op->builtin_options_as_SubOptions();
765 param.activation = convertActivation(sub_options->fused_activation_function());
768 case ir::operation::BinaryArithmetic::ArithmeticType::MUL:
770 const auto *mul_options = op->builtin_options_as_MulOptions();
771 param.activation = convertActivation(mul_options->fused_activation_function());
774 case ir::operation::BinaryArithmetic::ArithmeticType::DIV:
776 const auto *div_options = op->builtin_options_as_DivOptions();
777 param.activation = convertActivation(div_options->fused_activation_function());
782 "The function 'loadBinaryArithmetic' supports only BinaryArithmetic operations");
786 loadOperationTo<ir::operation::BinaryArithmetic>(op, subg, param);
789 template <typename LoaderDomain>
790 void BaseLoader<LoaderDomain>::loadPack(const Operator *op, ir::Graph &subg)
792 ir::operation::Pack::Param param;
793 const auto *options = op->builtin_options_as_PackOptions();
794 param.num = options->values_count();
795 param.axis = options->axis();
797 loadOperationTo<ir::operation::Pack>(op, subg, param);
800 template <typename LoaderDomain>
801 void BaseLoader<LoaderDomain>::loadElementwiseActivation(
802 const Operator *op, ir::Graph &subg, ir::operation::ElementwiseActivation::Type op_type,
803 float alpha, float beta)
805 ir::operation::ElementwiseActivation::Param param;
806 param.op_type = op_type;
810 loadOperationTo<ir::operation::ElementwiseActivation>(op, subg, param);
813 template <typename LoaderDomain>
814 void BaseLoader<LoaderDomain>::loadResizeBilinear(const Operator *op, ir::Graph &subg)
816 ir::operation::ResizeBilinear::Param param;
817 param.align_corners = op->builtin_options_as_ResizeBilinearOptions()->align_corners();
818 param.half_pixel_centers = op->builtin_options_as_ResizeBilinearOptions()->half_pixel_centers();
820 loadOperationTo<ir::operation::ResizeBilinear>(op, subg, param);
823 template <typename LoaderDomain>
824 void BaseLoader<LoaderDomain>::loadResizeNearestNeighbor(const Operator *op, ir::Graph &subg)
826 ir::operation::ResizeNearestNeighbor::Param param;
827 param.align_corners = op->builtin_options_as_ResizeNearestNeighborOptions()->align_corners();
829 loadOperationTo<ir::operation::ResizeNearestNeighbor>(op, subg, param);
832 template <typename LoaderDomain>
833 void BaseLoader<LoaderDomain>::loadReduce(const Operator *op, ir::Graph &subg,
834 ir::operation::Reduce::ReduceType reduce_type)
836 ir::operation::Reduce::Param param;
837 param.reduce_type = reduce_type;
838 param.keep_dims = op->builtin_options_as_ReducerOptions()->keep_dims();
840 loadOperationTo<ir::operation::Reduce>(op, subg, param);
843 template <typename LoaderDomain>
844 void BaseLoader<LoaderDomain>::loadReduceAll(const Operator *op, ir::Graph &subg)
846 ir::operation::Reduce::Param param;
847 param.reduce_type = ir::operation::Reduce::ReduceType::ALL;
848 if (op->custom_options() == nullptr)
850 param.keep_dims = false;
854 size_t custom_op_data_size = op->custom_options()->size();
855 auto custom_op_data = op->custom_options()->Data();
856 auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
857 auto attr_map = data_root.AsMap();
858 param.keep_dims = attr_map["keep_dims"].AsBool();
861 loadOperationTo<ir::operation::Reduce>(op, subg, param);
864 template <typename LoaderDomain>
865 void BaseLoader<LoaderDomain>::loadElementwiseBinary(
866 const Operator *op, ir::Graph &subg,
867 ir::operation::ElementwiseBinary::ElementwiseBinaryType op_type)
869 ir::operation::ElementwiseBinary::Param param;
870 param.op_type = op_type;
872 loadOperationTo<ir::operation::ElementwiseBinary>(op, subg, param);
875 template <typename LoaderDomain>
876 void BaseLoader<LoaderDomain>::loadElementwiseUnary(const Operator *op, ir::Graph &subg,
877 ir::operation::ElementwiseUnary::Type op_type)
879 ir::operation::ElementwiseUnary::Param param;
880 param.op_type = op_type;
882 const auto eu = loadOperationTo<ir::operation::ElementwiseUnary>(op, subg, param);
883 if (op_type == ir::operation::ElementwiseUnary::Type::CAST)
885 auto qasymm8ToUint8 = [](ir::Operand &operand) {
886 if (operand.typeInfo().type() == ir::DataType::QUANT_UINT8_ASYMM)
888 operand.type(ir::DataType::UINT8);
892 subg.operands().at(eu->getInputs().at(ir::operation::ElementwiseUnary::Input::INPUT)));
893 qasymm8ToUint8(subg.operands().at(eu->getOutputs().at(0)));
897 template <typename LoaderDomain>
898 void BaseLoader<LoaderDomain>::loadGather(const Operator *op, ir::Graph &subg)
900 ir::operation::Gather::Param param;
901 param.axis = op->builtin_options_as_GatherOptions()->axis();
903 loadOperationTo<ir::operation::Gather>(op, subg, param);
906 template <typename LoaderDomain>
907 void BaseLoader<LoaderDomain>::loadBatchMatMul(const Operator *op, ir::Graph &subg)
909 ir::operation::BatchMatMul::Param param;
911 const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
915 case BuiltinOperator::BuiltinOperator_BATCH_MATMUL:
916 param.adj_x = op->builtin_options_as_BatchMatMulOptions()->adjoint_lhs();
917 param.adj_y = op->builtin_options_as_BatchMatMulOptions()->adjoint_rhs();
919 case BuiltinOperator::BuiltinOperator_CUSTOM:
920 if (op->custom_options() == nullptr)
927 size_t custom_op_data_size = op->custom_options()->size();
928 auto custom_op_data = op->custom_options()->Data();
929 auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
930 auto attr_map = data_root.AsMap();
931 param.adj_x = attr_map["adj_x"].AsBool();
932 param.adj_y = attr_map["adj_y"].AsBool();
936 throw std::runtime_error(
937 std::string("Wrong loaded operation: ").append(EnumNameBuiltinOperator(builtin_op)) +
938 " as " + EnumNameBuiltinOperator(BuiltinOperator::BuiltinOperator_BATCH_MATMUL));
941 loadOperationTo<ir::operation::BatchMatMul>(op, subg, param);
944 template <typename LoaderDomain>
945 void BaseLoader<LoaderDomain>::loadSpaceToDepth(const Operator *op, ir::Graph &subg)
947 ir::operation::SpaceToDepth::Param param;
948 const auto *options = op->builtin_options_as_SpaceToDepthOptions();
949 param.block_size = options->block_size();
951 loadOperationTo<ir::operation::SpaceToDepth>(op, subg, param);
954 template <typename LoaderDomain>
955 void BaseLoader<LoaderDomain>::loadCustom(const Operator *op, ir::Graph &subg)
957 ir::OperandIndexSequence inputs;
958 ir::OperandIndexSequence outputs;
960 assert(op->custom_options_format() == CustomOptionsFormat::CustomOptionsFormat_FLEXBUFFERS &&
961 "Unsupported custom operation options format");
963 auto *op_code = _model->operator_codes()->Get(op->opcode_index());
964 auto custom_op_name = op_code->custom_code()->str();
975 StatelessRandomUniform,
979 // Mapping from custom op name string to BuiltinOP enum
980 std::map<std::string, BuiltinOP> builtin_map = {
981 {"AddV2", BuiltinOP::AddV2},
982 {"All", BuiltinOP::ReduceAll},
983 {"MatrixBandPart", BuiltinOP::MatrixBandPart},
984 {"BatchMatMulV2", BuiltinOP::BatchMatMul},
985 {"Einsum", BuiltinOP::Einsum},
986 {"FusedBatchNormV3", BuiltinOP::FusedBatchNorm},
987 {"BroadcastTo", BuiltinOP::BroadcastTo},
988 {"StatelessRandomUniform", BuiltinOP::StatelessRandomUniform},
989 {"Erf", BuiltinOP::Erf},
994 // Throw out_of_range if it is unknown custom op
995 auto custom_op_id = builtin_map.at(custom_op_name);
996 switch (custom_op_id)
998 case BuiltinOP::AddV2:
1001 case BuiltinOP::ReduceAll:
1002 loadReduceAll(op, subg);
1004 case BuiltinOP::MatrixBandPart:
1005 loadOperationTo<ir::operation::MatrixBandPart>(op, subg);
1007 case BuiltinOP::BatchMatMul:
1008 loadBatchMatMul(op, subg);
1010 case BuiltinOP::Einsum:
1011 loadEinsum(op, subg);
1013 case BuiltinOP::BroadcastTo:
1014 loadOperationTo<ir::operation::BroadcastTo>(op, subg);
1016 case BuiltinOP::FusedBatchNorm:
1017 loadFusedBatchNorm(op, subg);
1019 case BuiltinOP::StatelessRandomUniform:
1020 loadOperationTo<ir::operation::StatelessRandomUniform>(op, subg);
1022 case BuiltinOP::Erf:
1023 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ERF);
1026 throw std::runtime_error{
1027 "Loader: Custom OP map is defined but operation loader function is not defined"};
1034 loadOperationIO(op, inputs, outputs);
1036 auto constraint = ir::OperandConstraint::createExact(inputs.size());
1038 size_t custom_op_data_size = op->custom_options()->size();
1039 auto custom_op_data = new char[custom_op_data_size];
1040 std::copy(op->custom_options()->begin(), op->custom_options()->end(), custom_op_data);
1042 ir::operation::Custom::Userdata userdata{};
1043 userdata.data = custom_op_data;
1044 userdata.size = custom_op_data_size;
1046 auto new_op = std::make_unique<ir::operation::Custom>(constraint, inputs, outputs,
1047 custom_op_name, userdata);
1049 subg.addOperation(std::move(new_op));
1053 template <typename LoaderDomain>
1054 void BaseLoader<LoaderDomain>::loadSqueeze(const Operator *op, ir::Graph &subg)
1056 ir::operation::Squeeze::Param param;
1057 const auto *options = op->builtin_options_as_SqueezeOptions();
1058 const auto *dims = options->squeeze_dims();
1061 if (dims->size() > sizeof(param.dims) / sizeof(param.dims[0]))
1062 throw std::runtime_error("Squeeze: 'param.ndims' is out of range.");
1063 param.ndim = dims->size();
1064 for (int i = 0; i < param.ndim; ++i)
1065 param.dims[i] = dims->Get(i);
1068 loadOperationTo<ir::operation::Squeeze>(op, subg, param);
1071 template <typename LoaderDomain>
1072 void BaseLoader<LoaderDomain>::loadSplit(const Operator *op, ir::Graph &subg)
1074 ir::operation::Split::Param param;
1075 const auto *options = op->builtin_options_as_SplitOptions();
1076 param.num_splits = options->num_splits();
1078 loadOperationTo<ir::operation::Split>(op, subg, param);
1081 template <typename LoaderDomain>
1082 void BaseLoader<LoaderDomain>::loadSplitV(const Operator *op, ir::Graph &subg)
1084 ir::operation::SplitV::Param param;
1085 const auto *options = op->builtin_options_as_SplitVOptions();
1086 param.num_splits = options->num_splits();
1088 loadOperationTo<ir::operation::SplitV>(op, subg, param);
1091 template <typename LoaderDomain>
1092 void BaseLoader<LoaderDomain>::loadStridedSlice(const Operator *op, ir::Graph &subg)
1094 ir::operation::StridedSlice::Param param;
1095 const auto *options = op->builtin_options_as_StridedSliceOptions();
1096 param.begin_mask = options->begin_mask();
1097 param.end_mask = options->end_mask();
1098 param.shrink_axis_mask = options->shrink_axis_mask();
1100 loadOperationTo<ir::operation::StridedSlice>(op, subg, param);
1103 template <typename LoaderDomain>
1104 void BaseLoader<LoaderDomain>::loadUnpack(const Operator *op, ir::Graph &subg)
1106 ir::operation::Unpack::Param param;
1107 const auto *options = op->builtin_options_as_UnpackOptions();
1108 param.num = options->num();
1109 param.axis = options->axis();
1111 loadOperationTo<ir::operation::Unpack>(op, subg, param);
1114 template <typename LoaderDomain>
1115 void BaseLoader<LoaderDomain>::loadComparison(const Operator *op, ir::Graph &subg)
1117 ir::operation::Comparison::Param param;
1118 const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
1122 case BuiltinOperator::BuiltinOperator_EQUAL:
1123 param.comparison_type = ir::operation::Comparison::ComparisonType::Equal;
1125 case BuiltinOperator::BuiltinOperator_NOT_EQUAL:
1126 param.comparison_type = ir::operation::Comparison::ComparisonType::NotEqual;
1128 case BuiltinOperator::BuiltinOperator_GREATER_EQUAL:
1129 param.comparison_type = ir::operation::Comparison::ComparisonType::GreaterEqual;
1131 case BuiltinOperator::BuiltinOperator_GREATER:
1132 param.comparison_type = ir::operation::Comparison::ComparisonType::Greater;
1134 case BuiltinOperator::BuiltinOperator_LESS_EQUAL:
1135 param.comparison_type = ir::operation::Comparison::ComparisonType::LessEqual;
1137 case BuiltinOperator::BuiltinOperator_LESS:
1138 param.comparison_type = ir::operation::Comparison::ComparisonType::Less;
1141 throw std::runtime_error(
1142 std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op)));
1145 loadOperationTo<ir::operation::Comparison>(op, subg, param);
1148 template <typename LoaderDomain>
1149 void BaseLoader<LoaderDomain>::loadEinsum(const Operator *op, ir::Graph &subg)
1151 ir::operation::Einsum::Param param;
1152 if (op->custom_options() == nullptr)
1154 throw std::runtime_error{"Einsum: empty equation"};
1158 size_t custom_op_data_size = op->custom_options()->size();
1159 auto custom_op_data = op->custom_options()->Data();
1160 auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
1161 auto attr_map = data_root.AsMap();
1162 param.equation = attr_map["equation"].ToString();
1165 const auto es = loadOperationTo<ir::operation::Einsum>(op, subg, param);
1166 if (es->getInputs().size() != 2)
1168 throw std::runtime_error{"Einsum: NYI input - only support two inputs"};
1171 template <typename LoaderDomain>
1172 void BaseLoader<LoaderDomain>::loadFusedBatchNorm(const Operator *op, ir::Graph &subg)
1174 ir::operation::FusedBatchNorm::Param param;
1175 if (op->custom_options() == nullptr)
1177 throw std::runtime_error{"FusedBatchNorm: empty option"};
1181 size_t custom_op_data_size = op->custom_options()->size();
1182 auto custom_op_data = op->custom_options()->Data();
1183 auto data_root = flexbuffers::GetRoot(custom_op_data, custom_op_data_size);
1184 auto attr_map = data_root.AsMap();
1185 param.is_training = attr_map["is_training"].AsBool();
1186 param.epsilon = attr_map["epsilon"].AsFloat();
1187 param.data_format = attr_map["data_format"].ToString();
1190 const auto fbn = loadOperationTo<ir::operation::FusedBatchNorm>(op, subg, param);
1192 if (fbn->getInputs().size() != 5)
1194 throw std::runtime_error{"FusedBatchNorm: NYI input - only support five inputs"};
1198 template <typename LoaderDomain>
1199 void BaseLoader<LoaderDomain>::loadOneHot(const Operator *op, ir::Graph &subg)
1201 if (op->inputs()->size() != 4 || op->outputs()->size() != 1)
1202 throw std::runtime_error("OneHot Op has wrong number of input or output tensors.");
1205 ir::operation::OneHot::Param param;
1206 param.axis = op->builtin_options_as_OneHotOptions()->axis();
1208 loadOperationTo<ir::operation::OneHot>(op, subg, param);
1211 template <typename LoaderDomain>
1212 void BaseLoader<LoaderDomain>::loadIf(const Operator *op, ir::Graph &subg)
1214 const auto *options = op->builtin_options_as_IfOptions();
1215 const int32_t then_index = options->then_subgraph_index();
1216 const int32_t else_index = options->else_subgraph_index();
1218 verifySubgraphIndex(then_index);
1219 verifySubgraphIndex(else_index);
1221 ir::operation::If::Param param;
1222 param.then_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(then_index)};
1223 param.else_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(else_index)};
1225 loadOperationTo<ir::operation::If>(op, subg, param);
1228 template <typename LoaderDomain>
1229 void BaseLoader<LoaderDomain>::loadWhile(const Operator *op, ir::Graph &subg)
1231 const auto *options = op->builtin_options_as_WhileOptions();
1232 const int32_t cond_index = options->cond_subgraph_index();
1233 const int32_t body_index = options->body_subgraph_index();
1235 verifySubgraphIndex(cond_index);
1236 verifySubgraphIndex(body_index);
1238 ir::operation::While::Param param;
1239 param.cond_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(cond_index)};
1240 param.body_subg_index = ir::SubgraphIndex{static_cast<uint32_t>(body_index)};
1242 loadOperationTo<ir::operation::While>(op, subg, param);
1245 template <typename LoaderDomain>
1246 void BaseLoader<LoaderDomain>::loadArgMinMax(const Operator *op, ir::Graph &subg, bool is_argmax)
1248 ir::operation::ArgMinMax::Param param;
1249 const auto output_type = is_argmax ? op->builtin_options_as_ArgMaxOptions()->output_type()
1250 : op->builtin_options_as_ArgMinOptions()->output_type();
1251 param.output_type = tensorTypeToDataType(output_type);
1252 param.is_arg_max = is_argmax;
1254 loadOperationTo<ir::operation::ArgMinMax>(op, subg, param);
1257 template <typename LoaderDomain>
1258 void BaseLoader<LoaderDomain>::loadLogSoftmax(const Operator *op, ir::Graph &subg)
1260 ir::operation::LogSoftmax::Param param;
1261 // In tflite, beta is fixed to 1.0 and axis is fixed to -1.
1265 loadOperationTo<ir::operation::LogSoftmax>(op, subg, param);
1268 template <typename LoaderDomain>
1269 void BaseLoader<LoaderDomain>::loadLeakyRelu(const Operator *op, ir::Graph &subg)
1271 float alpha = op->builtin_options_as_LeakyReluOptions()->alpha();
1272 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::LEAKY_RELU, alpha,
1276 template <typename LoaderDomain>
1277 void BaseLoader<LoaderDomain>::loadUnidirectionalSequenceLSTM(const Operator *op, ir::Graph &subg)
1279 ir::operation::LSTM::Param param;
1280 const auto *options = op->builtin_options_as_UnidirectionalSequenceLSTMOptions();
1281 param.activation = convertActivation(options->fused_activation_function());
1282 param.cell_threshold = options->cell_clip();
1283 param.projection_threshold = options->proj_clip();
1284 param.time_major = options->time_major();
1285 // The asymmetric_quantize_inputs option is unused yet
1287 ir::OperandIndexSequence inputs;
1288 for (const std::int32_t idx : *op->inputs())
1290 inputs.append(tensorIdxToOperandIdx(idx));
1293 ir::OperandIndexSequence outputs;
1294 // loader doesn't support optional output tensor yet
1295 if (op->outputs()->size() != 1)
1297 auto builtin_code = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
1298 throw std::runtime_error(std::string("loader doesn't support optional output tensor yet for ")
1299 .append(EnumNameBuiltinOperator(builtin_code)));
1301 for (size_t i = 0; i < ir::operation::LSTM::Output::OUTPUT; ++i)
1303 // Add optional outputs
1304 outputs.append(ir::OperandIndex());
1306 outputs.append(tensorIdxToOperandIdx(op->outputs()->Get(0)));
1308 std::unique_ptr<ir::operation::LSTM> new_op(new ir::operation::LSTM(inputs, outputs, param));
1309 subg.addOperation(std::move(new_op));
1312 template <typename LoaderDomain>
1313 void BaseLoader<LoaderDomain>::loadOperation(const Operator *op, ir::Graph &subg)
1315 const auto builtin_op = _model->operator_codes()->Get(op->opcode_index())->builtin_code();
1319 case BuiltinOperator::BuiltinOperator_ADD_N:
1320 loadOperationTo<ir::operation::AddN>(op, subg);
1322 case BuiltinOperator::BuiltinOperator_CONV_2D:
1323 loadConv2D(op, subg);
1325 case BuiltinOperator::BuiltinOperator_AVERAGE_POOL_2D:
1326 loadPool2D(op, subg, ir::operation::Pool2D::PoolType::AVG);
1328 case BuiltinOperator::BuiltinOperator_DEPTHWISE_CONV_2D:
1329 loadDepthwiseConv2D(op, subg);
1331 case BuiltinOperator::BuiltinOperator_TRANSPOSE_CONV:
1332 loadTransposeConv(op, subg);
1334 case BuiltinOperator::BuiltinOperator_RESHAPE:
1335 loadReshape(op, subg);
1337 case BuiltinOperator::BuiltinOperator_SOFTMAX:
1338 loadSoftmax(op, subg);
1340 case BuiltinOperator::BuiltinOperator_MAX_POOL_2D:
1341 loadPool2D(op, subg, ir::operation::Pool2D::PoolType::MAX);
1343 case BuiltinOperator::BuiltinOperator_CONCATENATION:
1344 loadConcatenation(op, subg);
1346 case BuiltinOperator::BuiltinOperator_FLOOR:
1347 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::FLOOR);
1349 case BuiltinOperator::BuiltinOperator_FULLY_CONNECTED:
1352 case BuiltinOperator::BuiltinOperator_ADD:
1353 loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::ADD);
1355 case BuiltinOperator::BuiltinOperator_SUB:
1356 loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::SUB);
1358 case BuiltinOperator::BuiltinOperator_MUL:
1359 loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::MUL);
1361 case BuiltinOperator::BuiltinOperator_DIV:
1362 loadBinaryArithmetic(op, subg, ir::operation::BinaryArithmetic::ArithmeticType::DIV);
1364 case BuiltinOperator::BuiltinOperator_PACK:
1367 case BuiltinOperator::BuiltinOperator_ELU:
1368 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::ELU);
1370 case BuiltinOperator::BuiltinOperator_RELU:
1371 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU,
1372 ir::operation::ElementwiseActivation::infinity, 0.f);
1374 case BuiltinOperator::BuiltinOperator_RELU_N1_TO_1:
1375 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU, 1.f,
1378 case BuiltinOperator::BuiltinOperator_RELU6:
1379 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::RELU, 6.f,
1382 case BuiltinOperator::BuiltinOperator_RESIZE_BILINEAR:
1383 loadResizeBilinear(op, subg);
1385 case BuiltinOperator::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR:
1386 loadResizeNearestNeighbor(op, subg);
1388 case BuiltinOperator::BuiltinOperator_RSQRT:
1389 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::RSQRT);
1391 case BuiltinOperator::BuiltinOperator_SELECT:
1392 case BuiltinOperator::BuiltinOperator_SELECT_V2:
1393 loadOperationTo<ir::operation::Select>(op, subg);
1395 case BuiltinOperator::BuiltinOperator_SQRT:
1396 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::SQRT);
1398 case BuiltinOperator::BuiltinOperator_SQUARE:
1399 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::SQUARE);
1401 case BuiltinOperator::BuiltinOperator_SQUARED_DIFFERENCE:
1402 loadOperationTo<ir::operation::SquaredDifference>(op, subg);
1404 case BuiltinOperator::BuiltinOperator_TANH:
1405 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::TANH, 1.f,
1408 case BuiltinOperator::BuiltinOperator_TRANSPOSE:
1409 loadOperationTo<ir::operation::Transpose>(op, subg);
1411 case BuiltinOperator::BuiltinOperator_MEAN:
1412 loadReduce(op, subg, ir::operation::Reduce::ReduceType::MEAN);
1414 case BuiltinOperator::BuiltinOperator_REDUCE_ANY:
1415 loadReduce(op, subg, ir::operation::Reduce::ReduceType::ANY);
1417 case BuiltinOperator::BuiltinOperator_REDUCE_MAX:
1418 loadReduce(op, subg, ir::operation::Reduce::ReduceType::MAX);
1420 case BuiltinOperator::BuiltinOperator_REVERSE_V2:
1421 loadOperationTo<ir::operation::Reverse>(op, subg);
1423 case BuiltinOperator::BuiltinOperator_PAD:
1424 case BuiltinOperator::BuiltinOperator_PADV2:
1425 loadOperationTo<ir::operation::Pad>(op, subg);
1427 case BuiltinOperator::BuiltinOperator_LOGISTIC:
1428 loadElementwiseActivation(op, subg, ir::operation::ElementwiseActivation::Type::LOGISTIC);
1430 case BuiltinOperator::BuiltinOperator_EXP:
1431 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::EXP);
1433 case BuiltinOperator::BuiltinOperator_EXPAND_DIMS:
1434 loadOperationTo<ir::operation::ExpandDims>(op, subg);
1436 case BuiltinOperator::BuiltinOperator_GATHER:
1437 loadGather(op, subg);
1439 case BuiltinOperator::BuiltinOperator_SPACE_TO_BATCH_ND:
1440 loadOperationTo<ir::operation::SpaceToBatchND>(op, subg);
1442 case BuiltinOperator::BuiltinOperator_BATCH_TO_SPACE_ND:
1443 loadOperationTo<ir::operation::BatchToSpaceND>(op, subg);
1445 case BuiltinOperator::BuiltinOperator_SUM:
1446 loadReduce(op, subg, ir::operation::Reduce::ReduceType::SUM);
1448 case BuiltinOperator::BuiltinOperator_CUSTOM:
1449 loadCustom(op, subg);
1451 case BuiltinOperator::BuiltinOperator_SQUEEZE:
1452 loadSqueeze(op, subg);
1454 case BuiltinOperator::BuiltinOperator_PRELU:
1455 loadOperationTo<ir::operation::PReLU>(op, subg);
1457 case BuiltinOperator::BuiltinOperator_SPLIT:
1458 loadSplit(op, subg);
1460 case BuiltinOperator::BuiltinOperator_SPLIT_V:
1461 loadSplitV(op, subg);
1463 case BuiltinOperator::BuiltinOperator_SLICE:
1464 loadOperationTo<ir::operation::Slice>(op, subg);
1466 case BuiltinOperator::BuiltinOperator_STRIDED_SLICE:
1467 loadStridedSlice(op, subg);
1469 case BuiltinOperator::BuiltinOperator_UNPACK:
1470 loadUnpack(op, subg);
1472 case BuiltinOperator::BuiltinOperator_MINIMUM:
1473 loadElementwiseBinary(op, subg, ir::operation::ElementwiseBinary::ElementwiseBinaryType::MIN);
1475 case BuiltinOperator::BuiltinOperator_MAXIMUM:
1476 loadElementwiseBinary(op, subg, ir::operation::ElementwiseBinary::ElementwiseBinaryType::MAX);
1478 case BuiltinOperator::BuiltinOperator_CAST:
1479 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::CAST);
1481 case BuiltinOperator::BuiltinOperator_EQUAL:
1482 case BuiltinOperator::BuiltinOperator_NOT_EQUAL:
1483 case BuiltinOperator::BuiltinOperator_GREATER_EQUAL:
1484 case BuiltinOperator::BuiltinOperator_GREATER:
1485 case BuiltinOperator::BuiltinOperator_LESS_EQUAL:
1486 case BuiltinOperator::BuiltinOperator_LESS:
1487 loadComparison(op, subg);
1489 case BuiltinOperator::BuiltinOperator_ONE_HOT:
1490 loadOneHot(op, subg);
1492 case BuiltinOperator::BuiltinOperator_ABS:
1493 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ABS);
1495 case BuiltinOperator::BuiltinOperator_COS:
1496 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::COS);
1498 case BuiltinOperator::BuiltinOperator_SIN:
1499 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::SIN);
1501 case BuiltinOperator::BuiltinOperator_SHAPE:
1502 loadOperationTo<ir::operation::Shape>(op, subg);
1504 case BuiltinOperator::BuiltinOperator_REDUCE_PROD:
1505 loadReduce(op, subg, ir::operation::Reduce::ReduceType::PROD);
1507 case BuiltinOperator::BuiltinOperator_IF:
1510 case BuiltinOperator::BuiltinOperator_WHILE:
1511 loadWhile(op, subg);
1513 case BuiltinOperator::BuiltinOperator_NEG:
1514 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::NEG);
1516 case BuiltinOperator::BuiltinOperator_ARG_MAX:
1517 loadArgMinMax(op, subg, true);
1519 case BuiltinOperator::BuiltinOperator_ARG_MIN:
1520 loadArgMinMax(op, subg, false);
1522 case BuiltinOperator::BuiltinOperator_LOG:
1523 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::LOG);
1525 case BuiltinOperator::BuiltinOperator_ROUND:
1526 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ROUND);
1528 case BuiltinOperator::BuiltinOperator_POW:
1529 loadOperationTo<ir::operation::Pow>(op, subg);
1531 case BuiltinOperator::BuiltinOperator_LOGICAL_NOT:
1532 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::LOGICAL_NOT);
1534 case BuiltinOperator::BuiltinOperator_LOGICAL_AND:
1535 loadElementwiseBinary(op, subg,
1536 ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_AND);
1538 case BuiltinOperator::BuiltinOperator_LOGICAL_OR:
1539 loadElementwiseBinary(op, subg,
1540 ir::operation::ElementwiseBinary::ElementwiseBinaryType::LOGICAL_OR);
1542 case BuiltinOperator::BuiltinOperator_FILL:
1543 loadOperationTo<ir::operation::Fill>(op, subg);
1545 case BuiltinOperator::BuiltinOperator_ZEROS_LIKE:
1546 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::ZEROS_LIKE);
1548 case BuiltinOperator::BuiltinOperator_TILE:
1549 loadOperationTo<ir::operation::Tile>(op, subg);
1551 case BuiltinOperator::BuiltinOperator_RANGE:
1552 loadOperationTo<ir::operation::Range>(op, subg);
1554 case BuiltinOperator::BuiltinOperator_BATCH_MATMUL:
1555 loadBatchMatMul(op, subg);
1557 case BuiltinOperator::BuiltinOperator_LOG_SOFTMAX:
1558 loadLogSoftmax(op, subg);
1560 case BuiltinOperator::BuiltinOperator_QUANTIZE:
1561 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::QUANTIZE);
1563 case BuiltinOperator::BuiltinOperator_DEQUANTIZE:
1564 loadElementwiseUnary(op, subg, ir::operation::ElementwiseUnary::Type::DEQUANTIZE);
1566 case BuiltinOperator::BuiltinOperator_SPACE_TO_DEPTH:
1567 loadSpaceToDepth(op, subg);
1569 case BuiltinOperator::BuiltinOperator_L2_NORMALIZATION:
1570 loadOperationTo<ir::operation::L2Normalization>(op, subg);
1572 case BuiltinOperator::BuiltinOperator_LEAKY_RELU:
1573 loadLeakyRelu(op, subg);
1575 case BuiltinOperator::BuiltinOperator_RANK:
1576 loadOperationTo<ir::operation::Rank>(op, subg);
1578 case BuiltinOperator::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM:
1579 loadUnidirectionalSequenceLSTM(op, subg);
1581 case BuiltinOperator::BuiltinOperator_DEPTH_TO_SPACE:
1582 loadDepthToSpace(op, subg);
1585 throw std::runtime_error(
1586 std::string("Unsupported operation: ").append(EnumNameBuiltinOperator(builtin_op)));
1590 template <typename LoaderDomain> void BaseLoader<LoaderDomain>::loadModel()
1592 LoaderDomain::VerifyModelBuffer(*_verifier.get());
1593 _model = LoaderDomain::GetModel(_base);
1595 // const auto version = _model->version();
1596 // Description unused
1597 // const auto *description = _model->description();
1598 // Metabuffer unsued
1599 // const auto *metadata_buffer = _model->metadata_buffer();
1600 // Load subgraphs and map operations on subgraph
1601 const auto domain_subgraphs = _model->subgraphs();
1602 auto subgraphs = std::make_unique<ir::Subgraphs>();
1603 for (uint32_t subgraph_index = 0; subgraph_index < domain_subgraphs->size(); ++subgraph_index)
1605 auto subg = loadSubgraph((*_model->subgraphs())[subgraph_index]);
1606 subgraphs->push(ir::SubgraphIndex{subgraph_index}, std::move(subg));
1608 _subgraphs = std::move(subgraphs);
1611 } // namespace base_loader
1612 } // namespace onert
1614 #endif //__BASE_LOADER_BASE_LOADER_H__